Compare commits

..

No commits in common. "main" and "we-have-go-2" have entirely different histories.

147 changed files with 976 additions and 4031 deletions

768
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -9,14 +9,13 @@ repository = "https://github.com/Xe/site"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
axum = { version = "0.5", features = ["headers"] }
axum = "0.5"
axum-macros = "0.2"
axum-extra = "0.3"
color-eyre = "0.6"
chrono = "0.4"
comrak = "0.14.0"
comrak = "0.12.1"
derive_more = "0.99"
dirs = "4"
envy = "0.4"
estimated_read_time = "1"
futures = "0.3"
@ -28,13 +27,11 @@ 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.13", default-features = false, features = ["process"] }
rand = "0"
regex = "1"
reqwest = { version = "0.11", features = ["json"] }
serde_dhall = "0.11.2"
serde_dhall = "0.11.0"
serde = { version = "1", features = ["derive"] }
serde_yaml = "0.8"
sitemap = "0.4"
@ -48,11 +45,9 @@ 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" }
xe_jsonfeed = { path = "./lib/jsonfeed" }
jsonfeed = { path = "./lib/jsonfeed" }
mi = { path = "./lib/mi" }
patreon = { path = "./lib/patreon" }

View File

@ -7,7 +7,7 @@ tags:
---
[*Last time in the christine dot website cinematic
universe:*](https://xeiaso.net/blog/unix-domain-sockets-2021-04-01)
universe:*](https://christine.website/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:*

View File

@ -1,65 +0,0 @@
---
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>

View File

@ -1,175 +0,0 @@
---
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!

View File

@ -21,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://xeiaso.net/blog/nixos-desktop-flow-2020-04-25) with this M1
3600](https://christine.website/blog/nixos-desktop-flow-2020-04-25) with this M1
MacBook Air.
My tower is running this version of Rust:

View File

@ -181,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://xeiaso.net
- xesite -> https://christine.website
- graphviz -> https://graphviz.christine.website
- idp -> https://idp.christine.website
- oragono -> ircs://irc.within.website:6697/

View File

@ -1,125 +0,0 @@
---
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".

View File

@ -78,7 +78,7 @@ for this:
```
Xe Iaso (zi ai-uh-so)
https://xeiaso.net
https://christine.website
.i la budza pu cusku lu
<<.i ko snura .i ko kanro

View File

@ -36,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://xeiaso.net/resume)
If you feel comfortable doing so, I'd also suggest putting your [resume](https://christine.website/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).
@ -47,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://xeiaso.net/blog) on my blog, sometimes not even about
put [articles](https://christine.website/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.

View File

@ -54,7 +54,7 @@ by it. That attempt to come out failed and I was put into Christian
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
email](https://christine.website/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.

View File

@ -21,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://xeiaso.net/blog/the-cult-of-kubernetes-2019-09-07
[cultk8s]: https://christine.website/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

View File

@ -1,205 +0,0 @@
---
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.

View File

@ -82,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://xeiaso.net/blog/all-there-is-is-now-2019-05-25). Nobody
yet](https://christine.website/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

View File

@ -279,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://xeiaso.net/blog/dhall-kubernetes-2020-01-25)) and then
[here](https://christine.website/blog/dhall-kubernetes-2020-01-25)) and then
runs
[`scripts/release.sh`](https://tulpa.dev/cadey/printerfacts/src/branch/master/scripts/release.sh):

View File

@ -67,7 +67,7 @@ Hopefully Valve can improve the state of VR on Linux with the "deckard".
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
Dread](https://christine.website/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.

View File

@ -1,95 +0,0 @@
---
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>

View File

@ -8,7 +8,7 @@ series: conlangs
`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://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.
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.
## Phonology

View File

@ -363,14 +363,14 @@ my blog's [JSONFeed](/blog.json):
#!/usr/bin/env bash
# xeblog-post.sh
curl -s https://xeiaso.net/blog.json | jq -r '.items[0] | "\(.title) \(.url)"'
curl -s https://christine.website/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
Anbernic RG280M Review https://christine.website/blog/rg280m-review
```
What else could you do with pipes and redirection? The cloud's the limit!

View File

@ -16,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://xeiaso.net/blog/getting-started-with-go-2015-01-28
[gswg]: https://christine.website/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.

View File

@ -20,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://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
- 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
This is a continuation of the following two posts:
- https://xeiaso.net/blog/the-origin-of-h-2015-12-14
- https://xeiaso.net/blog/formal-grammar-of-h-2019-05-19
- https://christine.website/blog/the-origin-of-h-2015-12-14
- https://christine.website/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).

View File

@ -14,7 +14,7 @@ goes into hitting enter on christine.website and this website being loaded.
## Beginnings
The user types in `https://xeiaso.net` into the address bar and hits
The user types in `https://christine.website` 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

View File

@ -46,7 +46,7 @@ the Rust compiler.
[nixos]: https://nixos.org/nixos/
[nix]: https://nixos.org/nix/
[howistartnix]: https://xeiaso.net/blog/how-i-start-nix-2020-03-08
[howistartnix]: https://christine.website/blog/how-i-start-nix-2020-03-08
## A new project

View File

@ -10,7 +10,7 @@ From time to time, I am outright wrong on my blog. This is one of those times.
In my [last post about Nix][nixpost], I didn't see the light yet. I think I do
now, and I'm going to attempt to clarify below.
[nixpost]: https://xeiaso.net/blog/thoughts-on-nix-2020-01-28
[nixpost]: https://christine.website/blog/thoughts-on-nix-2020-01-28
Let's talk about a more simple scenario: writing a service in Go. This service
will depend on at least the following:

View File

@ -453,7 +453,7 @@ module. Here's how I do it:
You can add this to your `imports` in your server's `configuration.nix` using
[the layout I described in this
post](https://xeiaso.net/blog/morph-setup-2021-04-25). This would go in
post](https://christine.website/blog/morph-setup-2021-04-25). This would go in
the host-specific configuration folder.
Once you've deployed this to a server, try to open the page in your browser:

View File

@ -308,19 +308,19 @@ And then you can register it in your `network.nix` like this:
This should help you get your servers wrangled into a somewhat consistent state.
From here the following articles may be useful to give you ideas:
- [Borg Backup Config](https://xeiaso.net/blog/borg-backup-2021-01-09)
- [Borg Backup Config](https://christine.website/blog/borg-backup-2021-01-09)
- [Nixops Services On Your Home
Network](https://xeiaso.net/blog/nixops-services-2020-11-09) (just be
Network](https://christine.website/blog/nixops-services-2020-11-09) (just be
sure to ignore the part where it mentions `deployment.keys`, you can replace
it with the semantically identical
[`deployment.secrets`](https://github.com/DBCDK/morph/blob/master/examples/secrets.nix)
as described in the morph documentation)
- [Prometheus and
Aegis](https://xeiaso.net/blog/aegis-prometheus-2021-04-05)
Aegis](https://christine.website/blog/aegis-prometheus-2021-04-05)
- [My Automagic NixOS Wireguard
Setup](https://xeiaso.net/blog/my-wireguard-setup-2021-02-06)
Setup](https://christine.website/blog/my-wireguard-setup-2021-02-06)
- [Encrypted Secrets with
NixOS](https://xeiaso.net/blog/nixos-encrypted-secrets-2021-01-20)
NixOS](https://christine.website/blog/nixos-encrypted-secrets-2021-01-20)
Also feel free to dig around [the `common` folder of my `nixos-configs`
repo](https://github.com/Xe/nixos-configs/tree/master/common). There's a bunch

View File

@ -3,12 +3,6 @@ title: My Career So Far in Dates/Titles/Salaries
date: 2019-03-14
---
<div class="warning"><xeblog-conv name="Cadey" mood="coffee">This post is
outdated, see <a href="/salary-transparency">here</a> for more context on why
this data is made public. The table on this page will be automatically updated
to contain the data on my salary transparency page, but you should prefer that
page over this one when possible.</xeblog-conv></div>
Let this be inspiration to whoever is afraid of trying, failing and being fired.
Every single one of these jobs has taught me lessons I've used daily in my
career.
@ -32,7 +26,20 @@ might not want.
The following table is a history of my software career by title, date and salary
(company names are omitted).
<xeblog-salary-history></xeblog-salary-history>
| Title | Start Date | End Date | Days Worked | Days Between Jobs | Salary | How I Left |
|:----- |:---------- |:-------- |:----------- |:----------------- |:------ |:---------- |
| Junior Systems Administrator | November 11, 2013 | January 06, 2014 | 56 days | n/a | $50,000/year | Terminated |
| Software Engineering Intern | July 14, 2014 | August 27, 2014 | 44 days | 189 days | $35,000/year | Terminated |
| Consultant | September 17, 2014 | October 15, 2014 | 28 days | 21 days | $90/hour | Contract Lapsed |
| Consultant | October 27, 2014 | Feburary 9, 2015 | 105 days | 12 days | $90/hour | Contract Lapsed |
| Site Reliability Engineer | March 30, 2015 | March 7, 2016 | 343 days | 49 days | $125,000/year | Demoted |
| Systems Administrator | March 8, 2016 | April 1, 2016 | 24 days | 1 day | $105,000/year | Bad terms |
| Member of Technical Staff | April 4, 2016 | August 3, 2016 | 121 days | 3 days | $135,000/year | Bad terms |
| Software Engineer | August 24, 2016 | November 22, 2016 | 90 days | 21 days | $105,000/year | Terminated |
| Consultant | Feburary 13, 2017 | November 13, 2017 | 273 days | 83 days | don't remember | Hired |
| Senior Software Engineer | November 13, 2017 | March 8, 2019 | 480 days | 0 days | $150,000/year | Voulntary quit |
| Senior Site Reliability Expert | May 6, 2019 | October 27, 2020 | 540 days | 48 days | CAD$115,000/year (about USD$ 80k and change) | Voluntary quit |
| Software Designer | December 14, 2020 | *current* | n/a | n/a | CAD$135,000/year (about USD$ 105k and change) | n/a |
Even though I've been fired three times, I don't regret my career as it's been
thus far. I've been able to work on experimental technology integrating into

View File

@ -17,7 +17,7 @@ One thing that I do a lot is run virtual machines. Some of these stick around, a
lot of them are very ephemeral. I also like being able to get into these VMs
quickly if I want to mess around with a given distribution or OS. Normally I'd
run these on [my gaming
tower](https://xeiaso.net/blog/nixos-desktop-flow-2020-04-25), however
tower](https://christine.website/blog/nixos-desktop-flow-2020-04-25), however
this makes my tower very load-bearing. I also want to play games sometimes on my
tower, and even though there have been many strides in getting games to run well
on Linux it's still not as good as I'd like it to be.

View File

@ -58,7 +58,7 @@ la budza pu cusku lu
> May you be at peace. May you be happy.
- Buddha
I will be reachable on the internet. See https://xeiaso.net/contact to
I will be reachable on the internet. See https://christine.website/contact to
see contact information that will help you reach out to me. If you can, please
direct replies to me@christine.website, that way I can read them after this
account gets disabled.
@ -70,7 +70,7 @@ From my world to yours,
--
Christine Dodrill
https://xeiaso.net
https://christine.website
```
la budza pu cusku lu

View File

@ -3,7 +3,7 @@ title: New Site
date: 2016-12-18
---
This post is now being brought to you by the new and improved [https://xeiaso.net](https://xeiaso.net).
This post is now being brought to you by the new and improved [https://christine.website](https://christine.website).
This content is [markdown](/api/blog/post?name=new-site-2016-12-18) rendered by
[Purescript](http://www.purescript.org/). The old [site](https://github.com/Xe/christine.website)
is now being retired in favor of [this one](https://github.com/Xe/site). The old

View File

@ -275,13 +275,13 @@ project is using the same tools.
project folder I do not have any development tools
available.](conversation://Cadey/enby)
Flakes has the ability to specify this using the `devShells` flake output. You
Flakes has the ability to specify this using the `devShell` flake output. You
can add it to your `flake.nix` using this:
```nix
# after apps
# after defaultApp
devShells = forAllSystems (system:
devShell = forAllSystems (system:
let pkgs = nixpkgsFor.${system};
in {
default = pkgs.mkShell {
@ -422,7 +422,7 @@ world. To use a private repo, your flake input URL should look something like
this:
```
git+ssh://git@github.com/user/repo?ref=main
git+ssh://git@github.com:user/repo
```
[I'm pretty sure you could use private git repos outside of flakes, however it

View File

@ -72,7 +72,7 @@ Everything else we'll cover today will build on top of this.
Let's look back at the Go [example
package](https://github.com/Xe/gohello/blob/caf54cdff7d8dd9bd9df4b3b783a72fe75c9a11e/flake.nix#L31-L54)
I walked us through in [the last
post](https://xeiaso.net/blog/nix-flakes-1-2022-02-21):
post](https://christine.website/blog/nix-flakes-1-2022-02-21):
```nix
# ...

View File

@ -140,5 +140,5 @@ for more information.
---
Also happy December! My site has the [snow
CSS](https://xeiaso.net/blog/let-it-snow-2018-12-17) loaded for the
CSS](https://christine.website/blog/let-it-snow-2018-12-17) loaded for the
month. Enjoy!

View File

@ -6,7 +6,7 @@ author: ectamorphic
Recently I got a new VR setup that uses my tower directly instead of the [wifi
streaming
catastrophe](https://xeiaso.net/blog/convoluted-vrchat-gchat-setup-2021-02-24).
catastrophe](https://christine.website/blog/convoluted-vrchat-gchat-setup-2021-02-24).
I have a [Valve Index](https://store.steampowered.com/valveindex) and an [AMD
RX6700XT](https://www.amd.com/en/products/graphics/amd-radeon-rx-6700-xt) GPU.
Some huge advantages of this setup include:

View File

@ -5,10 +5,10 @@ date: 2019-01-17
I found an old backup that contained a few articles from my old [Medium](https://medium.com/@theprincessxena) blog. I have converted them to markdown and added them to the blog archives:
- 2014-11-28 - [Web Application Development with Beego](https://xeiaso.net/blog/beego-2014-11-28)
- 2014-11-20 - [Dependency Hell](https://xeiaso.net/blog/dependency-hell-2014-11-20)
- 2014-11-18 - [My Experience with Atom as A Vim User](https://xeiaso.net/blog/atom-as-vim-2014-11-18)
- 2014-10-24 - [Instant Development Environments in Docker](https://xeiaso.net/blog/dev-2014-10-24)
- 2014-10-20 - [MPD Via Docker](https://xeiaso.net/blog/mpd-docker-2014-10-20)
- 2014-11-28 - [Web Application Development with Beego](https://christine.website/blog/beego-2014-11-28)
- 2014-11-20 - [Dependency Hell](https://christine.website/blog/dependency-hell-2014-11-20)
- 2014-11-18 - [My Experience with Atom as A Vim User](https://christine.website/blog/atom-as-vim-2014-11-18)
- 2014-10-24 - [Instant Development Environments in Docker](https://christine.website/blog/dev-2014-10-24)
- 2014-10-20 - [MPD Via Docker](https://christine.website/blog/mpd-docker-2014-10-20)
I hope these are at all useful.

View File

@ -4,7 +4,7 @@ date: 2018-09-05
series: olin
---
This post is a continuation of [this post](https://xeiaso.net/blog/olin-1-why-09-1-2018).
This post is a continuation of [this post](https://christine.website/blog/olin-1-why-09-1-2018).
Suppose you are given the chance to throw out the world and start from scratch
in a minimal environment. You can then work up from nothing and build the world

View File

@ -13,7 +13,7 @@ tags:
Over the last week or so I've been doing a _lot_ of improvements to [Olin][olin] in order to make it ready to be the kernel for the minimum viable product of [wasmcloud][wasmcloud-hello-world]. Here's an overview of the big things that have happened from version [0.1.1][olin-0.1.1] to version [0.4.0][olin-0.4.0].
[olin]: https://github.com/Xe/olin
[wasmcloud-hello-world]: https://xeiaso.net/blog/wasmcloud-progress-2019-12-08
[wasmcloud-hello-world]: https://christine.website/blog/wasmcloud-progress-2019-12-08
[olin-0.1.1]: https://github.com/Xe/olin/releases/tag/v0.1.1
[olin-0.4.0]: https://github.com/Xe/olin/releases/tag/v0.4.0
@ -31,7 +31,7 @@ As Olin is just a kernel, it needs some work in order to really shine as a true
Here is what has been done since the [last Olin post][last-olin-post]:
[last-olin-post]: https://xeiaso.net/blog/olin-2-the-future-09-5-2018
[last-olin-post]: https://christine.website/blog/olin-2-the-future-09-5-2018
* An official, automated build of the example Olin components has been published to the Docker Hub
* The Go ABI has been deprecated for the moment

View File

@ -13,7 +13,7 @@ In my [last post][pahihelloworld] I mentioned that pa'i was faster than Olin's
cwa binary written in go without giving any benchmarks. I've been working on new
ways to gather and visualize these benchmarks, and here they are.
[pahihelloworld]: https://xeiaso.net/blog/pahi-hello-world-2020-02-22
[pahihelloworld]: https://christine.website/blog/pahi-hello-world-2020-02-22
Benchmarking WebAssembly implementations is slightly hard. A lot of existing
benchmark tools simply do not run in WebAssembly as is, not to mention inside

View File

@ -115,7 +115,7 @@ production-facing servers should probably only be able to be connected to over a
VPN of some kind.
If you want to see more about how to set up WireGuard on NixOS, see
[here](https://xeiaso.net/blog/my-wireguard-setup-2021-02-06) for more
[here](https://christine.website/blog/my-wireguard-setup-2021-02-06) for more
information.
## Locking Down the Hatches
@ -130,7 +130,7 @@ I am going to use the word "service" annoyingly vague here. In this world, a
"service" is a human-oriented view of "computer does the thing I want it to do".
This website you're reading this post on could be one service, and it should
have a separate account from other services. See
[here](https://xeiaso.net/blog/nixops-services-2020-11-09) for more
[here](https://christine.website/blog/nixops-services-2020-11-09) for more
information on how to set this up.
### Lock Down Services Within Systemd
@ -433,7 +433,7 @@ where I show you how to automatically create an ISO that does all this for you.
### Repeatable Base Image with an ISO
Using the setup I mentioned [in a past
post](https://xeiaso.net/blog/my-homelab-2021-06-08), you can create an
post](https://christine.website/blog/my-homelab-2021-06-08), you can create an
automatic install ISO that will take a blank disk to a state where you can SSH
into it and configure it further using a tool like
[morph](https://github.com/DBCDK/morph). Take a look at [this

View File

@ -9,7 +9,7 @@ tags:
- r13y
---
In [the last post](https://xeiaso.net/blog/paranoid-nixos-2021-07-18) we
In [the last post](https://christine.website/blog/paranoid-nixos-2021-07-18) we
covered a lot of the base groundwork involved in making a paranoid NixOS setup.
Today we're gonna throw this into prod by making a base NixOS image with it.

View File

@ -37,7 +37,7 @@ closest friends that I can talk about anything with, even what would normally
violate an NDA. My closest friends are so close that language isn't even as much
of a barrier as it would be otherwise.
As I've mentioned in the past, [I have tulpas](https://xeiaso.net/blog/what-its-like-to-be-me-2018-06-14).
As I've mentioned in the past, [I have tulpas](https://christine.website/blog/what-its-like-to-be-me-2018-06-14).
They are people that live with me like roommates inside my body. It really does
sound strange or psychotic; but you'll just have to trust me when I say they
fundamentally help me live my life, do my job and do other things people

View File

@ -14,7 +14,7 @@ My work laptop uses KDE, so I tried out
really liked this. I think one of the major differences between how I've been
failing at pomodoro in the past and why it's been working now is that I've
worked it into my [daily note-taking/TODO
workflow](https://xeiaso.net/blog/gtd-on-paper-2021-06-13). I label each
workflow](https://christine.website/blog/gtd-on-paper-2021-06-13). I label each
pomodoro (my notes call them "Pom" because that isn't something I write often in
them) as a section in my notes and then include a few TODO items under it. I'll
also add some notes to the pom in case I need them later.

View File

@ -49,12 +49,12 @@ Here is an example web app manifest [from my portfolio site](https://github.com/
"background_color": "#fa99ca",
"display": "standalone",
"scope": "/",
"start_url": "https://xeiaso.net/",
"start_url": "https://christine.website/",
"description": "Blog and Resume for Christine Dodrill",
"orientation": "any",
"icons": [
{
"src": "https://xeiaso.net/static/img/avatar.png",
"src": "https://christine.website/static/img/avatar.png",
"sizes": "1024x1024"
}
]
@ -65,7 +65,7 @@ If you just want to create a manifest quickly, check out [this](https://app-mani
## Add Manifest to Your Base HTML Template
I suggest adding the HTML link for the manifest to the most base HTML template you can, or in the case of a purely client side web app its main `index.html` file, as it needs to be as visible by the client trying to install the app. Adding this is [simple](https://developer.mozilla.org/en-US/docs/Web/Apps/Progressive/Installable_PWAs), assuming you are hosting this manifest on [/static/manifest.json](https://xeiaso.net/static/manifest.json) – simply add it to the <head> section:
I suggest adding the HTML link for the manifest to the most base HTML template you can, or in the case of a purely client side web app its main `index.html` file, as it needs to be as visible by the client trying to install the app. Adding this is [simple](https://developer.mozilla.org/en-US/docs/Web/Apps/Progressive/Installable_PWAs), assuming you are hosting this manifest on [/static/manifest.json](https://christine.website/static/manifest.json) – simply add it to the <head> section:
```html
<link rel="manifest" href="/static/manifest.json">
@ -96,7 +96,7 @@ At a high level, consider what assets and pages you want users of your website t
* Contact information for the person, company or service running the progressive web app
* Any other pages or information you might find useful for users of your website
For example, I have the following precached for [my portfolio site](https://xeiaso.net):
For example, I have the following precached for [my portfolio site](https://christine.website):
* My homepage (implicitly includes all of the CSS on the site) `/`
* My blog index `/blog/`

View File

@ -14,7 +14,7 @@ language help people understand where the boundaries between syllables are. I
will then describe my plans for the L'ewa orthography and how L'ewa is
romanized. This is a response to the prompt made [here][rclm2prompt].
[rclm1]: https://xeiaso.net/blog/reconlangmo-1-name-ctx-history-2020-05-05
[rclm1]: https://christine.website/blog/reconlangmo-1-name-ctx-history-2020-05-05
[rclm2prompt]: https://www.reddit.com/r/conlangs/comments/gfp3hw/reconlangmo_2_phonology_writing/
## Phonology

View File

@ -15,7 +15,7 @@ making the vocabulary for L'ewa and I'll include an entire table of the
dictionary words. This answers [this
prompt](https://www.reddit.com/r/conlangs/comments/gojncp/reconlangmo_6_lexicon/).
[reconlangmo]: https://xeiaso.net/blog/series/reconlangmo
[reconlangmo]: https://christine.website/blog/series/reconlangmo
## Word Distinctions

View File

@ -15,7 +15,7 @@ post will start to cover a lot of the softer skills behind L'ewa as well as
cover some other changes I'm making under the hood. This is a response to [this
prompt][rclm7].
[reconlangmo]: https://xeiaso.net/blog/series/reconlangmo
[reconlangmo]: https://christine.website/blog/series/reconlangmo
[rclm7]: https://www.reddit.com/r/conlangs/comments/gqo8jn/reconlangmo_7_discourse/
## Information Structure

View File

@ -103,7 +103,7 @@ this:
> I have no record of a "Christine Dodrill" at this email address. You may want
> to look elsewhere. If you would like to proceed with me instead, here is
> information about me: https://xeiaso.net.
> information about me: https://christine.website.
Throw in your pronouns too to be safe.

View File

@ -10,7 +10,7 @@ As of [a recent commit](https://github.com/Xe/site/commit/b89387f6bbb010907dfa85
to this site's code, it now generates RSS and Atom feeds for future posts on my
blog.
For RSS: `https://xeiaso.net/blog.rss`
For RSS: `https://christine.website/blog.rss`
For Atom: `https://christine.webiste/blog.atom`

View File

@ -38,7 +38,7 @@ my RTMP server. This means I could set it up to ingest via my [WireGuard
VPN][sts-wireguard] with very little work. Here is the docker command I run on
my VPN host:
[sts-wireguard]: https://xeiaso.net/blog/series/site-to-site-wireguard
[sts-wireguard]: https://christine.website/blog/series/site-to-site-wireguard
```console
$ docker run \

View File

@ -198,7 +198,7 @@ describes why functions fail to do what they intend. Rust has the [`Error`
trait](https://doc.rust-lang.org/std/error/trait.Error.html) which lets you also
create a type that describes why functions fail to do what they intend.
In [my last post](https://xeiaso.net/blog/TLDR-rust-2020-09-19) I
In [my last post](https://christine.website/blog/TLDR-rust-2020-09-19) I
described [`eyre`](https://docs.rs/eyre) and the Result type. However, this time
we're going to dive into [`thiserror`](https://docs.rs/thiserror) for making our
own error type. Let's add `thiserror` to our crate:

View File

@ -9,9 +9,9 @@ In this blogpost series I'm going to go over how I created a [site to site](http
This series is going to be broken up into multiple posts about as follows:
- Part 1 - Names and Numbers (this post)
- [Part 2 - DNS](https://xeiaso.net/blog/site-to-site-wireguard-part-2-2019-04-07)
- [Part 3 - Custom TLS Certificate Authority](https://xeiaso.net/blog/site-to-site-wireguard-part-3-2019-04-11)
- [Part 4 - HTTPS](https://xeiaso.net/blog/site-to-site-wireguard-part-4-2019-04-16)
- [Part 2 - DNS](https://christine.website/blog/site-to-site-wireguard-part-2-2019-04-07)
- [Part 3 - Custom TLS Certificate Authority](https://christine.website/blog/site-to-site-wireguard-part-3-2019-04-11)
- [Part 4 - HTTPS](https://christine.website/blog/site-to-site-wireguard-part-4-2019-04-16)
- Setting up additional iOS, macOS, Android and Linux clients
- Other future fun things (seamless tor2web routing, etc)

View File

@ -6,10 +6,10 @@ series: site-to-site-wireguard
This is the second in my Site to Site WireGuard VPN series. You can read the other articles here:
- [Part 1 - Names and Numbers](https://xeiaso.net/blog/site-to-site-wireguard-part-1-2019-04-02)
- [Part 1 - Names and Numbers](https://christine.website/blog/site-to-site-wireguard-part-1-2019-04-02)
- Part 2 - DNS (this post)
- [Part 3 - Custom TLS Certificate Authority](https://xeiaso.net/blog/site-to-site-wireguard-part-3-2019-04-11)
- [Part 4 - HTTPS](https://xeiaso.net/blog/site-to-site-wireguard-part-4-2019-04-16)
- [Part 3 - Custom TLS Certificate Authority](https://christine.website/blog/site-to-site-wireguard-part-3-2019-04-11)
- [Part 4 - HTTPS](https://christine.website/blog/site-to-site-wireguard-part-4-2019-04-16)
- Setting up additional iOS, macOS, Android and Linux clients
- Other future fun things (seamless tor2web routing, etc)
@ -230,7 +230,7 @@ $ dig @127.0.0.1 -x 10.55.0.1
### Using With the iOS WireGuard App
In order to configure [iOS WireGuard clients](https://itunes.apple.com/us/app/wireguard/id1441195209?mt=8) to use this DNS server, open the WireGuard app and tap the name of the configuration we created in the [last post](https://xeiaso.net/blog/site-to-site-wireguard-part-1-2019-04-02). Hit "Edit" in the upper right hand corner and select the "DNS Servers" box. Put `10.55.0.1` in it and hit "Save". Be sure to confirm the VPN is active, then open [LibTerm](https://itunes.apple.com/us/app/libterm/id1380911705?mt=8) and enter in the following:
In order to configure [iOS WireGuard clients](https://itunes.apple.com/us/app/wireguard/id1441195209?mt=8) to use this DNS server, open the WireGuard app and tap the name of the configuration we created in the [last post](https://christine.website/blog/site-to-site-wireguard-part-1-2019-04-02). Hit "Edit" in the upper right hand corner and select the "DNS Servers" box. Put `10.55.0.1` in it and hit "Save". Be sure to confirm the VPN is active, then open [LibTerm](https://itunes.apple.com/us/app/libterm/id1380911705?mt=8) and enter in the following:
```
$ dig oho.pele

View File

@ -6,10 +6,10 @@ series: site-to-site-wireguard
This is the third in my Site to Site WireGuard VPN series. You can read the other articles here:
- [Part 1 - Names and Numbers](https://xeiaso.net/blog/site-to-site-wireguard-part-1-2019-04-02)
- [Part 2 - DNS](https://xeiaso.net/blog/site-to-site-wireguard-part-2-2019-04-07)
- [Part 1 - Names and Numbers](https://christine.website/blog/site-to-site-wireguard-part-1-2019-04-02)
- [Part 2 - DNS](https://christine.website/blog/site-to-site-wireguard-part-2-2019-04-07)
- Part 3 - Custom TLS Certificate Authority (this post)
- [Part 4 - HTTPS](https://xeiaso.net/blog/site-to-site-wireguard-part-4-2019-04-16)
- [Part 4 - HTTPS](https://christine.website/blog/site-to-site-wireguard-part-4-2019-04-16)
- Setting up additional iOS, macOS, Android and Linux clients
- Other future fun things (seamless tor2web routing, etc)
@ -26,7 +26,7 @@ A TLS Certificate Authority is a certificate that is allowed to issue other cert
### Why Should I Create One?
Generally, it is useful to create a custom TLS certificate authority when there are custom DNS domains being used. This allows you to create `https://` links for your internal services (which can then act as [Progressive Web Apps](https://xeiaso.net/blog/progressive-webapp-conversion-2019-01-26)). This will also fully prevent the ["Not Secure"](https://versprite.com/blog/http-labeled-not-secure/) blurb from showing up in the URL bar.
Generally, it is useful to create a custom TLS certificate authority when there are custom DNS domains being used. This allows you to create `https://` links for your internal services (which can then act as [Progressive Web Apps](https://christine.website/blog/progressive-webapp-conversion-2019-01-26)). This will also fully prevent the ["Not Secure"](https://versprite.com/blog/http-labeled-not-secure/) blurb from showing up in the URL bar.
Sometimes your needs may involve needing to see what an application is doing over TLS traffic. Having a custom TLS certificate authority already set up makes this a much faster thing to do.

View File

@ -6,9 +6,9 @@ series: site-to-site-wireguard
This is the fourth post in my Site to Site WireGuard VPN series. You can read the other articles here:
- [Part 1 - Names and Numbers](https://xeiaso.net/blog/site-to-site-wireguard-part-1-2019-04-02)
- [Part 2 - DNS](https://xeiaso.net/blog/site-to-site-wireguard-part-2-2019-04-07)
- [Part 3 - Custom TLS Certificate Authority](https://xeiaso.net/blog/site-to-site-wireguard-part-3-2019-04-11)
- [Part 1 - Names and Numbers](https://christine.website/blog/site-to-site-wireguard-part-1-2019-04-02)
- [Part 2 - DNS](https://christine.website/blog/site-to-site-wireguard-part-2-2019-04-07)
- [Part 3 - Custom TLS Certificate Authority](https://christine.website/blog/site-to-site-wireguard-part-3-2019-04-11)
- Part 4 - HTTPS (this post)
- Setting up additional iOS, macOS, Android and Linux clients
- Other future fun things (seamless tor2web routing, etc)
@ -85,7 +85,7 @@ This will allow only Caddy and root to manage certificates in that folder.
### Custom CA Certificate Permissions
In the [last post](https://xeiaso.net/blog/site-to-site-wireguard-part-3-2019-04-11), custom certificates were created at `/srv/within/certs`. Caddy is going to need to have the correct permissions in order to be able to read them.
In the [last post](https://christine.website/blog/site-to-site-wireguard-part-3-2019-04-11), custom certificates were created at `/srv/within/certs`. Caddy is going to need to have the correct permissions in order to be able to read them.
```shell
#!/bin/sh

View File

@ -58,7 +58,7 @@ me](mailto:me@christine.website) and let me know them.
</noscript>
I want to use [Xeact](https://xeiaso.net/blog/xeact-0.0.69-2021-11-18)
I want to use [Xeact](https://christine.website/blog/xeact-0.0.69-2021-11-18)
more in my website. I am trying to hit a balance of avoiding structural
JavaScript while also allowing me to experiment with new and interesting ways of
doing things. To this end I have created a custom HTML element that allows me to

View File

@ -1,101 +0,0 @@
---
title: "Site Update: Hero Images"
date: 2022-06-08
---
For a while I've been wondering how I can add dramatic flair to my website with
so-called "hero images". These images are tools that let you describe the mood a
website wants to evoke. I've been unsure how to best implement these on my
website for a while, but with the advent of MidJourney and other image
generation APIs/algorithms I think I have found a way to create these without
too much effort on my part and the results are pretty fantastic:
<xeblog-hero file="secret-to-life" prompt="the secret to life, the universe and everything, concept art"></xeblog-hero>
I have generated a bunch of other images that I'm going to use for my other
posts. I'll give out a desktop wallpaper sized version of each of these images
on my [Patreon](https://patreon.com/cadey).
Under the hood this is powered by
[lol_html](https://github.com/cloudflare/lol-html) and
[Maud](https://maud.lambda.xyz/). The magic is mostly contained in a function
that generates a `<figure>` HTML element (which I just learned exists today). I
use a function that looks like this for generating the `<xeblog-hero>` snippets:
```rust
pub fn xeblog_hero(file: String, prompt: Option<String>) -> Markup {
html! {
figure.hero style="margin:0" {
picture style="margin:0" {
source type="image/avif" srcset={"https://cdn.xeiaso.net/file/christine-static/hero/" (file) ".avif"};
source type="image/webp" srcset={"https://cdn.xeiaso.net/file/christine-static/hero/" (file) ".webp"};
img style="padding:0" alt={"hero image " (file)} src={"https://cdn.xeiaso.net/file/christine-static/hero/" (file) "-smol.png"};
}
figcaption { "Image generated by MidJourney" @if let Some(prompt) = prompt { " -- " (prompt) } }
}
}
}
```
I have it wired up with lol_html like this:
```rust
lol_html::element!("xeblog-hero", |el| {
let file = el.get_attribute("file").expect("wanted xeblog-hero to contain file");
el.replace(&crate::tmpl::xeblog_hero(file, el.get_attribute("prompt")).0, ContentType::Html);
Ok(())
})
```
The result is that I can declare hero images with HTML fragments like this:
```html
<xeblog-hero file="miku-dark-souls" prompt="hatsune miku, elden ring, dark souls, concept art, crowbar"></xeblog-hero>
```
And I get this:
<xeblog-hero file="miku-dark-souls" prompt="hatsune miku, elden ring, dark souls, concept art, crowbar"></xeblog-hero>
<xeblog-conv name="Mara" mood="hacker">This is powered by the
[`<figure>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure)
tag, which is a new discovery to us. This is probably one of the most useful
tags we never knew about and removed the need to write a bunch of annoying CSS
and HTML.</xeblog-conv>
The webp and AVIF versions of the hero images have a higher resolution version
so that it looks nicer on retina screens. However, the png versions of these are
locked to a resolution of 800x356 pixels because I was unable to crush them
below a size of half a megabyte at full resolution. Realistically, this should
only affect older browsers on slower hardware, so I don't expect this to have
too much impact on most users.
<xeblog-conv name="Cadey" mood="coffee">If you don't want to see these hero
images, you can remove them with a userstyle like this:
```css
figure.hero {
display: none;
}
```
</xeblog-conv>
I'm likely going to convert over most of my website templates to use Maud. I'm
very happy with it and I think it is incredibly useful to express your HTML in
Rust instead of something that has to be compiled to Rust. In practice it
reminds me of the Nim library [emerald](http://flyx.github.io/emerald/), which
lets you write HTML using Nim functions similar to how you use Maud.
Here's a few more examples of hero images I have generated:
<xeblog-hero file="the-forbidden-shape" prompt="the forbidden shape"></xeblog-hero>
<xeblog-hero file="great-wave-cyberpunk" prompt="the great wave off of kanagawa, cyberpunk, hanzi inscription"></xeblog-hero>
Normally I will only have one image per post and it will usually be after the
introduction paragraph. The prompt will usually be related to the article topic,
but sometimes I will take artistic liberty. If you have suggestions for prompts,
please [contact me](/contact) with those ideas.
I hope these updates on how I've been messing with my site are interesting. I'm
trying to capture the spirit of how I'm implementing these changes as well as
details of how everything fits together.

View File

@ -1,117 +0,0 @@
---
title: "Site Update: I Fixed the Patron Page"
date: 2022-05-18
---
So I fixed [the patron page](https://xeiaso.net/patrons) and the
underlying issue was stupid enough that I feel like explaining it so you all can
learn from my mistake.
<xeblog-conv name="Numa" mood="delet">For those of you playing the christine dot
website home game, look
[here](https://github.com/Xe/site/commit/e2b9f384bf4033eddf321b5b5020ac4847609b37)
to see the fix and play along!</xeblog-conv>
My blog is basically a thin wrapper around two basic things:
1. Markdown files (such as for this article you are reading right now)
2. Static files (such as for the CSS that is making this article look nice)
When I create a package out of my blog's code, I have a layout that resembles
the directory structure in my git repo:
```console
$ ls -l /nix/store/crc94hqyb546w3w9fzdyr8zvz3xf3p1j-xesite-2.4.0
total 64
dr-xr-xr-x 2 root root 4096 Dec 31 1969 bin/
dr-xr-xr-x 2 root root 20480 Dec 31 1969 blog/
-r--r--r-- 24 root root 8663 Dec 31 1969 config.dhall
dr-xr-xr-x 2 root root 4096 Dec 31 1969 css/
dr-xr-xr-x 2 root root 4096 Dec 31 1969 gallery/
-r--r--r-- 52 root root 5902 Dec 31 1969 signalboost.dhall
dr-xr-xr-x 12 root root 4096 Dec 31 1969 static/
dr-xr-xr-x 2 root root 4096 Dec 31 1969 talks/
```
Here is my git repo for comparison:
```console
$ ls -l
total 188
drwxr-xr-x 2 cadey users 20480 May 18 20:21 blog/
-rw-r--r-- 1 cadey users 77521 May 18 20:15 Cargo.lock
-rw-r--r-- 1 cadey users 1795 May 18 20:15 Cargo.toml
-rw-r--r-- 1 cadey users 198 Oct 30 2020 CHANGELOG.md
-rw-r--r-- 1 cadey users 2779 Apr 5 20:32 config.dhall
drwxr-xr-x 2 cadey users 4096 Apr 16 11:56 css/
-rw-r--r-- 1 cadey users 1325 Jan 15 2021 default.nix
drwxr-xr-x 2 cadey users 4096 Mar 15 2020 docs/
drwxr-xr-x 2 cadey users 4096 Mar 21 20:23 examples/
-rw-r--r-- 1 cadey users 1882 Apr 30 16:13 flake.lock
-rw-r--r-- 1 cadey users 6547 Apr 24 20:35 flake.nix
drwxr-xr-x 2 cadey users 4096 Jun 17 2020 gallery/
drwxr-xr-x 6 cadey users 4096 Mar 21 20:23 lib/
-rw-r--r-- 1 cadey users 887 Jan 1 2021 LICENSE
drwxr-xr-x 2 cadey users 4096 Dec 18 00:06 nix/
-rw-r--r-- 1 cadey users 1467 Feb 21 20:39 README.md
drwxr-xr-x 2 cadey users 4096 Mar 21 21:21 scripts/
-rw-r--r-- 1 cadey users 5902 May 18 16:44 signalboost.dhall
drwxr-xr-x 5 cadey users 4096 Apr 5 20:32 src/
drwxr-xr-x 12 cadey users 4096 Jan 10 17:22 static/
drwxr-xr-x 2 cadey users 4096 Nov 10 2021 talks/
drwxr-xr-x 4 cadey users 4096 Apr 16 09:56 target/
drwxr-xr-x 2 cadey users 4096 May 15 07:59 templates/
```
The main problem is that my site expects all of this to be in the current
working directory. In my site's systemd unit I have a launch script that looks
like this:
```nix
script = let site = packages.default;
in ''
export SOCKPATH=${cfg.sockPath}
export DOMAIN=${toString cfg.domain}
cd ${site}
exec ${site}/bin/xesite
'';
```
However the Nix store isn't writable by user code. My patreon API client looked
for its credentials in the current working directory. When I set it up on the
target server I put the credentials in `/srv/within/xesite/.patreon.json`,
thinking that the `WorkingDirectory` setting would make it Just Work:
```nix
WorkingDirectory = "/srv/within/xesite";
```
But this was immediately blown away by the `cd` command on line 4 of the script.
I have fixed this by making my Patreon client put its credentials in the home
directory explicitly with this fragment of code:
```rust
let mut p = dirs::home_dir().unwrap_or(".".into());
p.push(".patreon.json");
```
This will make the Patreon credentials get properly stored in the service's home
directory (which is writable). This will also make the patrons page work
persistently without having to manually rotate secrets every month.
Here's a good lesson for you all, make sure to print out the absolute path of
everything in error messages. For the longest time I had to debug this from this
error message:
```
patrons: xesite::app: ".patreon.json" does not exist
```
I was looking at the directory `/srv/within/xesite` and I saw it existing right
in front of my eyes. This made me feel like I was going crazy and I've been
putting off fixing it because of that. However, it's a simple fix and I was
blind.
<xeblog-conv name="Cadey"
mood="coffee">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</xeblog-conv>

View File

@ -1,42 +0,0 @@
---
title: "Site Update: Salary Transparency Page Added"
date: 2022-06-14
author: Sephie
---
<xeblog-hero file="miku-dark-souls" prompt="hatsune miku, elden ring, dark souls, concept art, crowbar"></xeblog-hero>
I have added a [salary transparency
page](https://xeiaso.net/salary-transparency) to the blog. This page lists my
salary for every job I've had in tech. I have had this data open to the public
for years, but I feel this should be more prominently displayed on my website.
As someone who has seen pay discrimination work in action first-hand, data is
one of the ways that we can end this pointless hiding of information that leads
to people being uninformed and hurt by their lack of knowledge. By laying my
hand out in the open like this, I hope to ensure that people are better informed
about how much money they can make, so that they can be paid equally for equal
work.
Raw, machine processable data (including employer names) is available at
`/api/salary_transparency.json`. The JSON format is not stable. Do not treat it as
such. I reserve the right to change the formatting or semantics of the JSON
format at any time without warning. The raw data is in `/dhall/jobHistory.dhall`
in my site's git repository.
I have also taken the time to make sure that the [old
post](https://xeiaso.net/blog/my-career-in-dates-titles-salaries-2019-03-14)
maintains an up-to-date list. I do not want to break semantics on my website
without a very good reason. By leaving the old post un-updated, I feel it would
be doing a disservice to the community.
Please consider publishing your salary data like this as well. By open,
voluntary transparency we can help to end stigmas around discussing pay and help
ensure that the next generations of people in tech are treated fairly. Stigmas
thrive in darkness but die in the light of day. You can help end the stigma by
playing your cards out in the open like this.
It can be scary to do this; however every person that does it will make it that
much more easy for the next person to do it.
Don't be afraid.

View File

@ -8,13 +8,13 @@ tags:
---
I made a little interactive fiction story! You can find it
[here](https://xeiaso.net/static/stories/spaceship.html). This was
[here](https://christine.website/static/stories/spaceship.html). This was
written as a result of a terrible idea I had after watching some QuakeCon
announcements.
I wonder if I can get away with using an `<iframe>` in 2021:
<iframe src="https://xeiaso.net/static/stories/spaceship.html" width="100%" height=500></iframe>
<iframe src="https://christine.website/static/stories/spaceship.html" width="100%" height=500></iframe>
This is adapted from [a twitter
thread](https://twitter.com/theprincessxena/status/1428479144699088903).

View File

@ -1,68 +0,0 @@
---
title: "Spearphishing: it can happen to you too"
date: 2022-07-09
tags:
- linkedin
- infosec
---
<xeblog-hero file="the-fool" prompt="The Fool in a woodcut tarot card style"></xeblog-hero>
For some reason, LinkedIn has become the de-facto social network for
professionals. It is viewed as a powerful networking and marketing site that
lets professionals communicate, find new opportunities and source talent at
eye-watering speed and rates. However, at the same time this also means that
LinkedIn becomes a treasure trove of data to enable spearphising attacks.
Let's consider [this attack against popular "play to earn" game Axie
Infinity](https://www.theblock.co/post/156038/how-a-fake-job-offer-took-down-the-worlds-most-popular-crypto-game).
The attackers had PDF based malware that allowed them to get access to a target
computer, so they needed someone to open a PDF to trigger the exploit chain that
let them gain a foothold. But they specifically wanted people that likely had
access to the crypto wallets that enable control of the blockchain. LinkedIn let
them filter by employees at the company behind Axie Infinity that were
developers and likely started spearphishing by role and seniority. The details
of the attack spell out that the attackers had set up a whole fake interview
process to convince the marks that the process was legitimate and they put the
malware in the offer letter. The attackers later gained access to the validator
wallets and then they were able to make off with over half a billion dollars
worth of cryptocurrency.
<xeblog-conv name="Numa" mood="delet">Maybe, just maybe you shouldn't store a
majority of the keys required to validate something on _the same computer_.
Especially if those keypairs control assets worth close to _half a billion
dollars_. Holy heck.</xeblog-conv>
The malware was in the offer letter. This is the kind of social engineering
attack that I bet any one of you reading this article could fall for. Hell, I'd
probably fall for this. This may be the wrong kind of take to have, but I'm
really starting to wonder if using LinkedIn so much is actually bad for
security. It's not just recruiters reading through LinkedIn anymore, it's also
threat actors that are trying to break in and do God knows what. Maybe we as an
industry should stop feeding all of that data into LinkedIn. Not only would it
give you less recruiter spam, maybe it'll make spearphishing attacks more
difficult too.
<xeblog-conv name="Cadey" mood="coffee">Also, yes we can't trust PDFs anymore,
especially after exploits like
[FORCEDENTRY](https://googleprojectzero.blogspot.com/2021/12/a-deep-dive-into-nso-zero-click.html)
became a thing.</xeblog-conv>
Either way, I may end up getting a disposable machine for dealing with reading
PDFs from unknown sources in the future. I could use a virtual machine for this,
but if my threat model includes PDFs having exploits in them then I probably
can't trust a virtual machine to be a reasonable security barrier. I don't know.
It sucks that we can't trust people anymore.
I kinda wish we could.
---
<xeblog-conv name="Mara" mood="hacker">Fun fact: the tarot card "The Fool"
doesn't actually imply idiocy in a malicious way. The major arcana of the tarot
is a bunch of memes that describe the story of The Fool's journey through magick
and learning how the world works. The Fool is not an idiot, The Fool is just
someone that is unaware of the difficulties they are going to face in life and
treats things optimistically. Think a free spirit as opposed to someone that is
foolhardy (though foolhardiness is the meaning of The Fool when the card is
inverted).</xeblog-conv>

View File

@ -26,7 +26,7 @@ problems that require deep thought and consideration.
I was originally gonna release this by the end of the year as a cohesive novel,
however it looks like the cards aren't falling that way. I want to instead shift
[Spellblade](https://xeiaso.net/blog/spellblade-plans-2021-08-16) into a
[Spellblade](https://christine.website/blog/spellblade-plans-2021-08-16) into a
web novel, which I am defining as something that I'll release in big chunks like
this every month or so. I don't want to compromise any of the artistic vision or
whatever, I just want each "chunk" to be a lot more finely scoped than "the

View File

@ -64,7 +64,7 @@ def get_feed(feed_url):
con.commit()
print("got feed %s" % (feed_url))
get_feed("https://xeiaso.net/blog.json")
get_feed("https://christine.website/blog.json")
```
So now let's play with the data! Let's load the database schema in with the
@ -76,14 +76,14 @@ $ sqlite3 data.db < schema.sql
[The less-than symbol there is a redirect, it loads the data from `schema.sql`
as standard input to the `sqlite` command. See <a
href="https://xeiaso.net/blog/fun-with-redirection-2021-09-22">here</a>
href="https://christine.website/blog/fun-with-redirection-2021-09-22">here</a>
for more information on redirections.](conversation://Mara/hacker)
Then run that python script to populate the database:
```console
$ python ./jsonfeedfetch.py
got feed https://xeiaso.net/blog.json
got feed https://christine.website/blog.json
```
Then open up the SQLite command line:
@ -179,7 +179,7 @@ And run that python script again, then the data should automatically show up:
```
sqlite3> SELECT * FROM jsonfeed_metadata;
https://xeiaso.net/blog.json|Xe's Blog|My blog posts and rants about various technology things.|https://xeiaso.net|2022-01-04
https://christine.website/blog.json|Xe's Blog|My blog posts and rants about various technology things.|https://christine.website|2022-01-04
```
It's like magic!

View File

@ -1,106 +0,0 @@
---
title: "The Stanley Parable: Ultra Deluxe Review"
date: 2022-07-25
series: reviews
---
Every so often a game comes around that is genuinely hard to review. Especially
when you are trying to avoid spoiling the magic of the game in that review. This
is a game that is even harder to review than normal because it's an absolute
philosophical document. This game absolutely riffs at the games industry super
hard and it really shows. I'm going to try to avoid spoilers in this article,
except for a few I made up.
<xeblog-conv name="Cadey" mood="coffee">I was going to include screenshots in
this article, but it's difficult for me to get them without spoiling the subtle
comedy at hand, so I'm going to leave this as a text-only review.</xeblog-conv>
The Stanley Parable: Ultra Deluxe is either the second or third game in the
series. At first this game was a Half Life 2 mod that came out of nowhere and
was one of the most beloved mods ever released. Then they made it a proper game
on the Source engine and expanded it a bit. After a while they wanted to
continue the parable and expand it even more, but they weren't able to get it on
consoles with it still being a Source engine game. So they ported it to Unity
and the end result is The Stanley Parable: Ultra Deluxe. It is one of my
favorite games of all time.
It is a deeply limited game, you only can move around and interact with things.
The story is about an office drone named Stanley that pushes buttons based on
instructions from his computer. The big thing that this game does though is make
you realize the inherent paradoxes in its own design.
<xeblog-conv name="Mara" mood="happy">Being mechanically limited like this is
not actually a bad thing like the phrasing might imply. This means that the main
focus of the gameplay is not on the micro actions the player can take. In this
case the main focus is on how the player interacts with the story and not how
the player interacts with their controller or puzzles or tactics. Additionally,
the mechanical limitations of the gameplay are thematically aligned with the
story's premise of being an office drone in ways it can play with. Think
dramatic irony taken to its logical conclusion.</xeblog-conv>
Endings that make you look like you had exercised your free will actually boil
down to your actions being controlled by following the narrator's voices. This
is absolutely taking the piss out of how most modern AAA game design works,
guiding you with an invisible hand and making it _seem_ like you had the free
will to choose what was going on when in fact you were really just following the
invisible guidance the whole time.
However I think one of the best examples of how The Stanley Parable riffs at
mainstream game design is via the Adventure Line™️ that shows up in one branch of
the game. The Line™️ is an obvious riff on games like Dead Space where you can
summon a line to tell you where to go at any time. It shows how _boring_ modern
game design is by making you _see_ the consequences of it. If you follow the
narrator's voice, you get boring endings.
In many modern AAA games, you have the free will to choose to follow the main
story and finish all the quests or whatever, but not much else. Consider Call of
Duty or Battlefield. You are John America and you have to kill the enemies to
death before they kill you to death by throwing bullets at you. You get to the
end of the level and blow up the brown people some more or something and then
it's suddenly a victory for America. But what did you really accomplish? You
just followed the line. Walk outside of the intended playable area? 10 second
timer until the game kills you. Shoot a person with the wrong skin color? The
game kills you.
<xeblog-conv name="Numa" mood="delet">If you manage to clip out of bounds in the
escape ending, the screen will fade to black and you will be transported to a
temperate climate. Then a t-posing model in terrible armor will tell you that it
used to be an adventurer until they took an arrow to the knee. Hope that's not a
marriage proposal!</xeblog-conv>
However in The Stanley Parable you can defy the narrator and that's where the
game really opens up. It's great to get in the area where the game is unfinished
and then have the narrator complain about deadlines, scheduling delays, investor
funding and them wanting to avoid having to stuff it to the gills with
microtransactions. You can legitimately glitch your way out of bounds and then
the game will reward you with a new ending you didn't know was possible. The
game takes the concept of the illusion of free will and plays with it.
The game makes you think about what games _can_ be. It makes you wonder if the
potted plant soliloquy after the broom closet ending speaks to the mental state
of the author more than anything. Of all of the artistic endeavors that games as
a medium _can_ have, we end up seeing very few or none of them in mainstream
gaming. Sure you get your occasional 4k120fps robot killer waifu with a bow and
a whacky stick, but none of it really _revolutionizes_ video games as an art
form. It's all just derivative of the generic "unalive bad guy and save earth"
trope.
<xeblog-conv name="Mara" mood="hacker">If you want some games that really
revolutionize what games can be, check out
[Celeste](https://mattmakesgames.itch.io/celeste), [Secret Little
Haven](https://ristar.itch.io/secret-little-haven), [Baba Is
You](https://hempuli.itch.io/baba), and [Glittermitten
Grove](https://twinbeard.itch.io/glittermitten-grove). All of these games really
challenge what games can be and experiment with radically different kinds of
art. You never will see mainstream games be as risk-taking as this because art
is fundamentally risky and capitalism wants line to go up, so they go out of
their way to make sure that mainstream games are as safe and likely to sell many
copies as possible.</xeblog-conv>
I made up the thing about the potted plant, but if you had played the game then
you'd probably have started the game up to look for it just to see what was
there. I wonder if I made someone stand at that potted plant for like 5 minutes
or something. This game sparks creativity in ways that other mainstream games
just fundamentally don't. If you've been looking for something different in your
video game diet, I really suggest you give it a try. Go in as blind as possible.
I'm not paid in any way to say this, I genuinely think this is really good.

View File

@ -4,7 +4,7 @@ date: 2019-05-30
series: templeos
---
The [last post](https://xeiaso.net/blog/templeos-1-installation-and-basic-use-2019-05-20) covered a lot of the basic usage of TempleOS. This post is going to be significantly different, as I'm going to be porting part of the TempleOS kernel to WebAssembly as a live demo.
The [last post](https://christine.website/blog/templeos-1-installation-and-basic-use-2019-05-20) covered a lot of the basic usage of TempleOS. This post is going to be significantly different, as I'm going to be porting part of the TempleOS kernel to WebAssembly as a live demo.
This post may contain words used in ways and places that look blasphemous at first glance. No blasphemy is intended, though it is an unfortunate requirement for covering this part of TempleOS' kernel. It's worth noting that Terry Davis [legitimately believed that TempleOS is a temple of the Lord Yahweh](https://templeos.holyc.xyz/Wb/Doc/Charter.html):

View File

@ -1,344 +0,0 @@
---
title: The Oasis
date: 2022-06-03
series: malto
tags:
- furry
---
Tosen did a final check of his backpack. It was a very hot day in Tashei, but
the river radiated an aura of cool air that protected everyone from the heat of
the harsh sun. He had his backup cloak, a hydroflask and some fish jerkey, not
to mention the package for the client. *Not exactly the best equipment but this
will work. Riltash is a half day away at worst,* Tosen thought to himself. He
squatted down and fit his arms into the pack's straps. The pack easily weighed a
quarter of what he did, but as he regained his catlike balance he secured the
waistband and got ready to head out.
The oracle predicted that there would be a sandstorm late in the evening, but it
wasn't even noon yet. He pulled out his compass, let it settle and then set out
to the southeast.
Walking in the desert always has its own unique rhythm to it. With the
unrelenting heat of the sun pounding down on the sand, the ground itself can
feel like a million angry daggers with every step. Tosen thought ahead of this
issue. He got himself a pair of sandshoes from the fancy magic item store. The
only downside was that his main connection to the earth was significantly
weakened. Chee paws are some of the most finely tuned sensory organs on Malto
(second only to Snep paws), and they were his main warning about sandstorms.
*The oracle isn't wrong most of the time. I'm fine, I'm fine. I can't feel the
desert but I'm fine.*
He kept walking past all different kinds of cacti. His favorite ones were the
ones that were made up of a bunch of spiky ovals built on top of eachother. He'd
never want to get stung by one and risk the wrath of the serrated needles, but
he'd always thought that they had such a unique look. *If I had a house of my
own, I'd grow one of them.*
As he continued walking he started to focus on the patterns of walking. Every
step was taken one after the other. With every step, his foot slid to the side
ever so slightly. The sand wrapped around his shoes and warmed his feet. The
worst part of the sandshoes was when sand trickled into the back of them. This
required him to stop every so often to purge the sand out of his shoes, because
otherwise it would hurt a lot.
This continued for what felt like hours. He checked his compass every so often
and made sure he was on the right path. It started to move a bit weird compared
to normal. It was taking longer to find north. Normally this would be concerning
to him, but the desert had entranced him. Left, right, left, right, left, right.
Each step bringing him closer to his destination.
Then the sky changed color. The brilliant blue started to get stained with a
light brown that worked its way across what Tosen could see. Tosen instantly
noticed this change and pulled over his face veil. The sandstorm had started
early. The oracle was wrong.
Tosen looked around for some kind of shelter but all he could see was the
remains of a broken wagon that looked like its better days had seen better days.
It was barely enough protection. With his spare robe to patch over the biggest
holes just enough to ride out the storm. He took the leap and hunkered down.
*It's only a level 2 storm. It'll be over in an hour. I'll make it to Riltash
today. Everything will work out.*
As he sat down he reached for his compass and couldn't find it. He reached into
the pocket that his compass normally lives in and felt it conspicuously empty.
He looked up towards the path he walked in on and saw a golden glint in the
sand. It was so close. If he could get to it, he'd know where to go. He'd find
his way to Riltash.
But the sandstorm started to kick up. The sky started fading towards darker and
darker shades of brown and he could feel the sand beat against his makeshift
shelter. The hot sand was whipped up and he could hear it pitter and patter the
wooden and cloth walls.
After an hour, the sandstorm started showing signs of slowing down. *This is
nothing close to a level 2*, Tosen thought to himself. His spare robe was
totally ruined, but he survived. As things died down, he remembered his compass
and tore down enough of his shelter to be able to find it. It wasn't where it
was before. *Okay, it's made of gold, it can't have gone that far*. He grabbed
his pack, almost fell over from the sudden weight and started to scan around him
in 360 degrees. He saw the familiar glint of its knob and walked over to its
resting site. The looking glass was cracked. Rotating it did nothing. The
compass was broken.
He was lost.
It took every ounce of strength Tosen had to avoid shouting out in anger. He
needed to conserve the water. Miau was huge. He needs to extend his supplies to
last as long as possible.
He couldn't resist the urge. He shouted out in anger for an instant before
realizing what he did and covering his mouth.
It took a while for Tosen to regain his senses. The shock of the event wasn't
sitting well with him. His mother's compass was destroyed. His rendezvous time
with the client was surely shot. At least it wasn't the solar apex anymore.
*Okay, I can deal with this. I should stay put until sunset. The sun sets to the
east. I can go diagonally into the sunset to get to Riltash*.
He more confidently went back to his makeshift shelter. It was in worse
condition after the storm, but at least it would give him shade. The sun was on
its way down, but it was still a deadly laser that he needed to worry about.
*It's just me and you, buddy.*
Some time passed and the sun very visibly was in the eastern portion of the sky.
Tosen grabbed for his hydroflask and took a sip. *It was still cold. At least
that oracle was good for SOMETHING.* He stood up and grabbed his pack. He left a
bit of red cloth as a flag on the southeast side of his makeshift shelter to
tell anyone looking for him where he went.
Then it was back to the rhythms of the desert. The desert felt confusing without
the comforting pulse of nature under his paws. But, he continued taking steps
and continued walking forwards.
Left. Right. Left. Right. Left. Right. Things felt more deliberate this time.
There was a frustration to his walking. He was so frustrated at the whole
situation. As he walked, he felt his emotions fuming over this whole debacle.
He walked and walked. The sunset had started to peek out its head and show Tosen
a display of fantastic colors as he continued to walk. *This isn't right. I
should have reached Riltash by now. It's only a few miles from Tashei.* He took
another swig of his hydroflask and felt it notably lighter than it should be. He
was low on water. This was especially dangerous out here. *This is going to be a
long night, isn't it.*
The sunset continued and the colors gradually started to fade to the black night
sky. Starts started to peek out without the sun to hide them. Tosen scanned over
the constellations and found the North Star. From there he worked out that he
was going to the southeast like he thought he was. He looked around and found a
few miserable bushes to use for firewood, but they were in a sea of thorns. He
had talents in fire magick, but he didn't trust using it with so many dry thorns
nearby. *You know what, what's the worst that can happen? I get warm? It's going
to be so cold soon, I need to do something.*
He held out his hand and mentally started to trace out the triangles like he
learned from school. Each triangle stacked on top of each other and then built
up into a viable casting circle glowing a brilliant orange in front of his hand.
The area around him was illuminated from the magickal force, the thorns casting
long evil shadows against cacti and other miserable little bushes.
"Toor sha!"
A weak puff of flame came out of his hand and tickled one of the thorny vines.
There wasn't much of a response and it looked like the fire was going to go out
so he cast a fireball in its place. The triangles shifted into squares and a
baseball sized orb of energy started to form in his hand.
"Toor shaltel!"
The fireball formed around his fingers and he chucked it right into the pit of
thorns. They were all set on fire simultaneously. After a brilliant blaze, the
fire petered out into nothing as fast as it started. He looked over to see if
the firewood was still there, his spell circle was still active as a flashlight
but that kindling was nowhere to be seen. It was incinerated with everything
else.
He had to resist shouting out in anger again. *Okay, okay, calm down. I set off
a massive signal fire. That should alert someone. I can't keep this spell circle
up, I'll mind down and then I'll be in worse trouble.* He killed off the spell
with a flick of the wrist and the darkness crept in. He was alone. I need to
keep walking. So he started walking, not realizing that he changed direction
after the incident with the thorns.
Left! Right! Left! Right! Left! Right! Each step felt angry and defiant. Tosen
started to feel legitimate anger at the desert. It was normally his home, he
grew up in the sands of Miau, but tonight it was his enemy. He defiantly marched
towards where he thought Riltash was, but got no closer.
It was a very long night walking towards town. It was a desperate, angry march.
He stopped a few times to take a bite of jerkey and swig it down with the bare
minimum of water he could get away with. He thought it would be colder, but it
turns out all that fur ended up going towards something.
The night continued and was broken by the inklings of a sunrise. Tosen looked up
in dismay. He had walked all night and he was nowhere closer to his destination.
An overwhelming feeling of sadness blanketed him and he broke down to start
crying.
He looked forward and saw something different. He saw what looked like the faint
outline of Riltash's signal statue. His sadness was instantly transmuted to a
mixture of relief and joy and his second wind started to hit. He trudged forward
towards that statue. Towards his salvation. Towards his client. Towards his
paycheck. Towards the next step to move out to Zhalram with his friends. Towards
his future.
He kept up his pace and got closer. The statue looked wrong. Riltash has the
visage of one of the water goddesses in the region. This looked different,
almost like a Chee. He wasn't aware of any local Chee deities. He looked down
and saw shimmers. It almost looked like a mirage, but then he remembered
something. There were rumors of an oasis south of Riltash. Could this be that?
Could there be water?
His second wind became a third and then a fourth wind. He got close enough to
take a better look at everything and it was that oasis!
*Water!*
His walk became a sprint and the sand started to be diluted with grass. As he
walked on the grass he suddenly felt an overwhelming sense of calm. It was as if
all of the anger, all the vitriol, all the hatred towards the desert vanished in
an instant. He paused for a moment but then continued on. The promise of fresh
water was too great. He was so thirsty.
He put his pack down, took off his shoes and tested the water with a paw. It was
cool to the touch, about 10 degrees celsius. It was the real deal. It was water.
He took off his robe, folded it haphazardly next to his pack and grabbed his
hydroflask. He opened it and shoved it under so it could be filled. Once he was
satisfied that it was full, he bent over and started to lap up the water
greedily.
A figure vaguely resembling the statue was watching from a nearby house. The
figure chuckled to themselves. They decided they should intervene. They donned a
white robe and walked out to the weary traveler.
Tosen was enamoured by the water. His exhaustion had finally caught up to him.
He looked back at his pack and saw a figure walking towards him from some kind
of house. He instantly jumped to alertness, but didn't feel the fear that
generally came with being startled like that. The figure felt familiar yet alien
somehow.
The figure looked at his pack and his visibly broken compass. They looked right
into Tosen's eyes. "Rough day?"
Tosen stammered a few times and eventually managed to come up with a reply:
"Y...yeah. I was caught in that sandstorm yesterday. I hid from it in a broken
wagon."
The figure reached out a hand to him. "Come with me. You need a rest. I'll come
back to take care of your things. I have a spare bed for travelers like you."
Tosen didn't have enough energy to argue with the stranger's offer of
hospitality and followed them into their house. They guided Tosen to the guest
room and sat on one of the chairs. Tosen collapsed on the most comfortable bed
he had ever felt in his life. All he could get out was a weak "thank....youuuu"
before his lost sleep caught up and he was out like a light. The figure pulled a
blanket over him and closed the shades to make the room nice and dark.
Tosen was asleep until the late afternoon. The figure had moved his stuff
inside, done his laundry, mended a hole in the pack and was lounging in a chair
for a nap of their own.
Tosen woke up, stretched out and yawned loudly. He looked up at the ceiling and
realized how unfamiliar it was. That angel in his dream was real. Had he
actually walked through the night? The figure knocked at the door. "Hey, come
and have a meal. You must be starving." He was. Tosen stood up and opened the
door. The figure was wearing a white robe and a golden necklace. They looked
like the archetypal vision of Chee beauty. Tosen noted that he was unable to
refer to that figure with any pronoun but "they". *That's weird...*
The figure started to speak: "I am Shal'tash. I saw you hurting and I decided to
intervene and help you. Come, I have some food almost ready." Shal'tash started
to walk towards the kitchen and Tosen followed. He made his way to a rather
ordinary looking wooden table and took a seat. His stuff was near the table and
he was grateful for his host's gratuity.
They were making pancakes. The batter was being poured into a metal pan in
little groups. Tosen noticed that the stove seemed to be powered by its own
magic circle, a non-organic magic emitter was being used to create the fire
needed for cooking. It was a weak burner, but it was enough for Shal'tash to
cook with.
Tosen was befuddled. He had never seen such a thing in action. He got up and
looked at it closely. Shal'tash looked back and smiled, "Never seen a stove
burner before?"
"Not like that no, it looks like it's casting a weak fire spell, but
constantly."
"This is a lot more efficient than the coal burning stoves you have. This lets
you use the energy equivalent of a fireball to get a half hour of cooking heat,
or an hour or two of torchlight. I'm surprised you didn't know about this."
Tosen looked confused. "You mean you can use the square level spell to
supercharge the triangle level spell? No, they never taught us this. But how is
the burner even working?"
Shal'tash laughed. "It's nothing special. I just rooted the circle under the pan
instead of on my hand. Here, you try it." They flicked their wrist and banished
the magic circle. "Now cast a fireball but focus on the pan instead of your
hand, let it simmer a bit, and then kick off create fire."
Tosen was confused but nodded and tried to comply. After a moment Shal'tash
piped in: "no, don't think about where the pan is relative to your hand. Think
about where the pan is relative to the pan. You're so close. I know you can do
it."
Tosen nodded and started over. The circle started to be inscribed below the pan
and Shal'tash's face lit up like a Christmas tree. "Toor sha!"
The burner was lit. The fire was continuously burning and Tosen didn't feel the
sting of a continuous cast. "Perfect. See how easy this is? Spend the mana on
the fireball, then use it for the weaker spell. No need to waste any."
Tosen was astounded. It normally took him ages to learn magical skills, but here
he was on the second try with this person and their vague instruction and he did
two things he thought was impossible. It was like magic was all new all over
again. Can I use this to make a bunch of fireballs when casting a firestorm? How
far does this go?
"Be careful with this, you could really hurt someone if you do displacement
foolishly. They must have stopped teaching it for a reason." Shal'tash finished
the stack of pancakes and put the plate in the middle of the table. "Now let's
eat!"
They shared a meal. It was just what Tosen needed.
The meal was finished. Shal'tash looked over to Tosen. "So where are you headed?
I can point you in the right direction."
"Riltash, I have a delivery that I'm incredibly late for by now."
Shal'tash chuckled and pointed towards the statue. "The statue points towards
Riltash. Just go straight north and you'll get there in 20 minutes."
Tosen looked incredulous. "I was really that close?"
"Yeah, though it looked like you needed to get lost. It can be good for you."
He didn't understand what they meant by that, but he didn't think he needed to.
Shal'tash walked with Tosen to the north side of the oasis. Tosen looked towards
his saviour and was suddenly overcome with emotion. "Thank you so much. You
saved me."
"You are welcome. I saved you because I was in a situation worse than yours when
I found this oasis. I don't want anyone to experience the pain that I have felt,
so I saved you before it could get that bad."
"What can I do to repay you?"
"You don't need to do anything right now. Just save someone else when you can.
If you want, come back here and give me a visit. It'd be fun to catch up,
Tosen."
"Thanks again! I'll be back!"
Tosen walked off towards his payday. He looked back every so often and the oasis
became more distant and then faded completely from sight into the rest of the
sands. He was alone again, but not in spirit.
He never noticed that they knew his name without him telling them his name.
Shal'tash walked back towards their house and stood by their cactus. They
watched as Tosen faded into the sands and then headed inside. Their job was
complete.

View File

@ -3,7 +3,7 @@ title: The Origin of h
date: 2015-12-14
---
NOTE: There is a [second part](https://xeiaso.net/blog/formal-grammar-of-h-2019-05-19) to this article now with a formal grammar.
NOTE: There is a [second part](https://christine.website/blog/formal-grammar-of-h-2019-05-19) to this article now with a formal grammar.
For a while I have been pepetuating a small joke between my friends, co-workers and community members of various communities (whether or not this has been beneficial or harmful is out of the scope of this post). The whole "joke" is that someone says "h", another person says "h" back.

View File

@ -8,7 +8,7 @@ tags:
---
EDIT(M02 20 2020): I've written a bit of a rebuttal to my own post
[here](https://xeiaso.net/blog/i-was-wrong-about-nix-2020-02-10). I am
[here](https://christine.website/blog/i-was-wrong-about-nix-2020-02-10). I am
keeping this post up for posterity.
I don't really know how I feel about [Nix][nix]. It's a functional package

View File

@ -42,7 +42,7 @@ how things changed:
As of the time of writing this post, it is January third, 2020 and the roadmap
is apparently to release V 0.2 this month.
Let's see what's been fixed since [my last article](https://xeiaso.net/blog/v-vaporware-2019-06-23).
Let's see what's been fixed since [my last article](https://christine.website/blog/v-vaporware-2019-06-23).
## Compile Speed

View File

@ -125,7 +125,7 @@ designing this, but I think the next character in my blog is going to be an
anthro snow leopard named Alicia. I want Alicia to be a beginner that is very
new to computer programming and other topics, which would then make Mara into
more of a teacher type. I may also introduce my own OC Cadey (the orca looking
thing you can see [here](https://xeiaso.net/static/img/avatar_large.png)
thing you can see [here](https://christine.website/static/img/avatar_large.png)
or in the favicon of my site) into the mix to reply to these questions in
something more close to the Socratic method.

View File

@ -37,7 +37,7 @@ Be well.
---
Every so often I like to check in on the [V Programming Language][vlang]. It's been
about six months since [my last post](https://xeiaso.net/blog/v-vvork-in-progress-2020-01-03),
about six months since [my last post](https://christine.website/blog/v-vvork-in-progress-2020-01-03),
so I thought I'd take another look at it and see what progress has been done in six
months.

View File

@ -51,10 +51,10 @@ job. TLS configuration is not its job. Its job is to run your code. Everything
else should just be provided by the system.
I wrote a
[blogpost](https://xeiaso.net/blog/land-1-syscalls-file-io-2018-06-18)
[blogpost](https://christine.website/blog/land-1-syscalls-file-io-2018-06-18)
about this work and even did a
[talk at GoCon
Canada](https://xeiaso.net/talks/webassembly-on-the-server-system-calls-2019-05-31)
Canada](https://christine.website/talks/webassembly-on-the-server-system-calls-2019-05-31)
about it.
And this worked for several months as I learned WebAssembly and started to
@ -93,8 +93,8 @@ people understand low-level operating system development.
I've even written a few blogposts about Olin:
- [Olin: Why](https://xeiaso.net/blog/olin-1-why-09-1-2018)
- [Olin: The Future](https://xeiaso.net/blog/olin-2-the-future-09-5-2018)
- [Olin: Why](https://christine.website/blog/olin-1-why-09-1-2018)
- [Olin: The Future](https://christine.website/blog/olin-2-the-future-09-5-2018)
But, this was great for running stuff interactively and via the command line. It
left me wanting more. I wanted to have that mythical functions as a service
@ -230,5 +230,5 @@ keep the dream alive!
[olincwa]: https://github.com/Xe/olin/tree/master/docs/cwa-spec
[olincwarust]: https://github.com/Xe/olin/tree/master/cwa/olin
[olincwatest]: https://github.com/Xe/olin/blob/master/cwa/tests/src/main.rs
[olintempleos]: https://xeiaso.net/blog/templeos-2-god-the-rng-2019-05-30
[olintempleos]: https://christine.website/blog/templeos-2-god-the-rng-2019-05-30
[wasmcloud]: https://tulpa.dev/within/wasmcloud

View File

@ -530,7 +530,7 @@ giving up when there is no more work to be done.
inside the Google monorepo that escaped out into the world. They also claim to
have an internal tool that makes
[`context.TODO()`](https://pkg.go.dev/context#TODO) useful (probably by showing
you the callsites above that function?), but they never released that tool as
you the callsities above that function?), but they never released that tool as
open source so it’s difficult to know where to use it without that added
context.</xeblog-conv>
@ -592,7 +592,7 @@ You can attach this to an HTTP request by using
[`http.NewRequestWithContext`](https://pkg.go.dev/net/http#NewRequestWithContext):
```go
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://xeiaso.net/.within/health", nil)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://christine.website/.within/health", nil)
```
And then when you execute the request (such as with `http.DefaultClient.Do(req)`)
@ -888,15 +888,9 @@ fuzzing, RISC-V support, binary/octal/hexadecimal/imaginary number literals,
WebAssembly support, so many garbage collector improvements and more. This has
added up to make Go a fantastic choice for developing server-side applications.
I, as some random person on the internet that is not associated with the Go
team, think that if there was sufficient political will that they could probably
label what we have as Go 2, but I don’t think that is going to happen any time
soon. Until then, we still have a very great set of building blocks that allow
you to make easy to maintain production quality services, and I don’t see that
changing any time soon.
---
<xeblog-conv name="Mara" mood="happy">If you had subscribed to the
[Patreon](https://patreon.com/cadey) you could have read this a week
ago!</xeblog-conv>
I, as some random person on the
internet that is not associated with the Go team, think that if there was
sufficient political will that they could probably label what we have as Go 2,
but I don’t think that is going to happen any time soon. Until then, we still
have a very great set of building blocks that allow you to make easy to maintain
production quality services, and I don’t see that changing any time soon.

View File

@ -15,4 +15,4 @@ of that talk has been posted.
I hope you enjoy! I have some more blogposts in the queue but I've been sleeping horribly lately. Here's hoping that clears up.
[goconcanada]: https://gocon.ca/
[talklink]: https://xeiaso.net/talks/webassembly-on-the-server-system-calls-2019-05-31
[talklink]: https://christine.website/talks/webassembly-on-the-server-system-calls-2019-05-31

View File

@ -31,7 +31,7 @@ $ curl https://mi.within.website/api/webmention/01ERGGEG7DCKRH3R7DH4BXZ6R9 | jq
{
"id": "01ERGGEG7DCKRH3R7DH4BXZ6R9",
"source_url": "https://maya.land/responses/2020/12/01/i-think-this-blog-post-might-have-been.html",
"target_url": "https://xeiaso.net/blog/toast-sandwich-recipe-2019-12-02",
"target_url": "https://christine.website/blog/toast-sandwich-recipe-2019-12-02",
"title": null
}
```

View File

@ -80,7 +80,7 @@ in one of a few ways:
Some concepts are pulled in from various documents and ideas in a slightly
[kasmakfa](https://write.as/excerpts/practical-kasmakfa) manner, but overall the
most "confusing" thing to new readers is going to be related to this comment in
the [anapana](https://xeiaso.net/blog/when-then-zen-anapana-2018-08-15)
the [anapana](https://christine.website/blog/when-then-zen-anapana-2018-08-15)
feature:
> Note: "the body" means the sack of meat and bone that you are currently living inside. For the purposes of explanation of this technique, please consider what makes you yourself separate from the body you live in.

View File

@ -32,7 +32,7 @@ This article is a more verbose version of [the correlating feature from when-the
The When Then Zen project aims to describe the finer points of meditative concepts in plain English. As such, we start assuming just about nothing and build fractally on top of concepts derived from common or plain English usage of the terms. Some of these techniques may be easier for people with a more intensive meditative background, but try things and see what works best for you. Meditation in general works a lot better when you have a curious and playful attitude about figuring things out.
I'm not perfect. I don't know what will work best for you. A lot of this is documenting both my practice and what parts of what books helped me "get it". If this works for you, [please let me know](https://xeiaso.net/contact). If this doesn't work for you, [please let me know](https://xeiaso.net/contact). I will use this information for making direct improvements to these documents.
I'm not perfect. I don't know what will work best for you. A lot of this is documenting both my practice and what parts of what books helped me "get it". If this works for you, [please let me know](https://christine.website/contact). If this doesn't work for you, [please let me know](https://christine.website/contact). I will use this information for making direct improvements to these documents.
As for your practice, twist the rules into circles and scrape out the parts that don't work if it helps you. Find out how to integrate it into your life in the best manner and go with it.

View File

@ -8,7 +8,7 @@ tags:
---
This website has been a progressive web app [for a long
time](https://xeiaso.net/blog/progressive-webapp-conversion-2019-01-26).
time](https://christine.website/blog/progressive-webapp-conversion-2019-01-26).
This means that you can install my blog to your phone as if it was a normal app
via the share menu in Safari on iOS or via other native prompts on other
browsers. However, this is not enough. In the constant pursuit of advancement I

View File

@ -1,64 +0,0 @@
---
title: How to Store an SSH Key on a Yubikey
date: 2022-05-27
series: howto
tags:
- yubikey
- security
---
SSH keys suck. They are a file on the disk and you can easily move it to other
machines instead of storing them in hardware where they can't be exfiltrated.
Using a password to encrypt the private key is a viable option, but the UX for
that is hot garbage. It's allegedly the future, so surely we MUST have some way
to make this all better, right?
<xeblog-conv name="Numa" mood="delet">\>implying there is a way to make anything
security related better</xeblog-conv>
Luckily, there is actually something we can do for this! As of [OpenSSH
8.2](https://www.openssh.com/releasenotes.html#8.2) (Feburary 14, 2020) you are
able to store an SSH private key on a yubikey! Here's how to do it.
<xeblog-conv name="Mara" mood="hacker">This should work on other FIDO keys like
Google's Titan, but we don't have access to one over here and as such haven't
tested it. Your mileage may vary. We are told that it works with the Google
Titan key that is handed out to Go contributors.</xeblog-conv>
First install `yubikey-manager` (see
[here](https://www.yubico.com/support/download/yubikey-manager/) for more
information, or run `nix-shell -p yubikey-manager` to run it without installing
it on NixOS), plug in your yubikey and run `ykman list`:
```console
$ ykman list
YubiKey 5C NFC (5.4.3) [OTP+FIDO+CCID] Serial: 4206942069
```
If you haven't set a PIN for the yubikey yet, follow
[this](https://docs.yubico.com/software/yubikey/tools/ykman/FIDO_Commands.html#ykman-fido-access-change-pin-options)
to set a PIN of your choice. Once you do this, you can generate a new SSH key
with the following command:
```
ssh-keygen -t ed25519-sk -O resident
```
<xeblog-conv name="Mara" mood="hacker">If that fails, try `ecdsa-sk`
instead! Some hardware keys may not support storing the key on the key
itself.</xeblog-conv>
Then enter in a super secret password (such as the Tongues you received as a kid
when you were forced into learning the bible against your will) twice and then
add that key to your agent with `ssh-add -K`. Then you can list your keys with
`ssh-add -L`:
```console
$ ssh-add -L
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIKgGePSwpBuHUhrFCRLch9Usqi7L0fKtgTRnh6F/R+ruAAAABHNzaDo= cadey@shachi
```
Then you can copy this public key to GitHub or whatever and authenticate as
normal. The private key is stored on your yubikey directly and you can add it
with `ssh-add -K`. You can delete the ssh key stub at `~/.ssh/id_ed25519_sk` and
then your yubikey will be the only thing holding that key.

View File

@ -8,7 +8,7 @@ tags:
---
As I mentioned
[before](https://xeiaso.net/blog/colemak-layout-2020-08-15), I ordered a
[before](https://christine.website/blog/colemak-layout-2020-08-15), I ordered a
[ZSA Moonlander](https://zsa.io/moonlander) and it has finally arrived. I am
writing this post from my Moonlander, and as such I may do a few more typos
than normal, I'm still getting used to this.

View File

@ -22,7 +22,7 @@ no influence pushing me either way on this keyboard.
desk](https://cdn.christine.website/file/christine-static/img/keeb/Elm3dN8XUAAYHws.jpg)
[That 3d printed brain is built from the 3D model that was made as a part of <a
href="https://xeiaso.net/blog/brain-fmri-to-3d-model-2019-08-23">this
href="https://christine.website/blog/brain-fmri-to-3d-model-2019-08-23">this
blogpost</a>.](conversation://Mara/hacker)
## tl;dr
@ -131,7 +131,7 @@ standard [Colemak](https://Colemak.com/) layout and it is currently the layer I
type the fastest on. I have the RGB configured so that it is mostly pink with
the homerow using a lighter shade of pink. The color codes come from my logo
that you can see in the favicon [or here for a larger
version](https://xeiaso.net/static/img/avatar_large.png).
version](https://christine.website/static/img/avatar_large.png).
I also have a qwerty layer for gaming. Most games expect qwerty keyboards and
this is an excellent stopgap to avoid having to rebind every game that I want to

View File

@ -1,11 +1,96 @@
let xesite = ./dhall/types/package.dhall
let Person =
{ Type =
{ name : Text
, tags : List Text
, gitLink : Optional Text
, twitter : Optional Text
}
, default =
{ name = ""
, tags = [] : List Text
, gitLink = None Text
, twitter = None Text
}
}
let Config = xesite.Config
let Author =
{ Type =
{ name : Text
, handle : Text
, picUrl : Optional Text
, link : Optional Text
, twitter : Optional Text
, default : Bool
, inSystem : Bool
}
, default =
{ name = ""
, handle = ""
, picUrl = None Text
, link = None Text
, twitter = None Text
, default = False
, inSystem = False
}
}
let defaultPort = env:PORT ? 3030
let defaultWebMentionEndpoint =
env:WEBMENTION_ENDPOINT
? "https://mi.within.website/api/webmention/accept"
let Config =
{ Type =
{ signalboost : List Person.Type
, authors : List Author.Type
, port : Natural
, clackSet : List Text
, resumeFname : Text
, webMentionEndpoint : Text
, miToken : Text
}
, default =
{ signalboost = [] : List Person.Type
, authors =
[ Author::{
, name = "Xe Iaso"
, handle = "xe"
, picUrl = Some "/static/img/avatar.png"
, link = Some "https://christine.website"
, twitter = Some "theprincessxena"
, default = True
, inSystem = True
}
, Author::{
, name = "Jessie"
, handle = "Heartmender"
, picUrl = Some
"https://cdn.christine.website/file/christine-static/img/UPRcp1pO_400x400.jpg"
, link = Some "https://heartmender.writeas.com"
, twitter = Some "BeJustFine"
, inSystem = True
}
, Author::{
, name = "Ashe"
, handle = "ectamorphic"
, picUrl = Some
"https://cdn.christine.website/file/christine-static/img/FFVV1InX0AkDX3f_cropped_smol.jpg"
, inSystem = True
}
, Author::{ name = "Nicole", handle = "Twi", inSystem = True }
, Author::{ name = "Mai", handle = "Mai", inSystem = True }
]
, port = defaultPort
, clackSet = [ "Ashlynn" ]
, resumeFname = "./static/resume/resume.md"
, webMentionEndpoint = defaultWebMentionEndpoint
, miToken = "${env:MI_TOKEN as Text ? ""}"
}
}
in Config::{
, signalboost = ./dhall/signalboost.dhall
, authors = ./dhall/authors.dhall
, signalboost = ./signalboost.dhall
, clackSet =
[ "Ashlynn", "Terry Davis", "Dennis Ritchie", "Steven Hawking" ]
, jobHistory = ./dhall/jobHistory.dhall
}

View File

@ -44,6 +44,17 @@ img {
padding-right: 1em;
}
/* xeblog-conv:not(:defined) { */
/* display: block; */
/* border-left: 0.25ch solid green; */
/* padding-left: 1.75ch; */
/* } */
/* xeblog-conv:before:not(:defined) { */
/* content: "<"attr(name)">"; */
/* font-weight: bold; */
/* } */
.warning {
background-color: #282828;
}

View File

@ -48,6 +48,7 @@ in pkgs.stdenv.mkDerivation {
cp -rf $src/blog $out/blog
cp -rf $src/css $out/css
cp -rf $src/gallery $out/gallery
cp -rf $src/signalboost.dhall $out/signalboost.dhall
cp -rf $src/static $out/static
cp -rf $src/talks $out/talks

View File

@ -1,30 +0,0 @@
let Author = ./types/Author.dhall
in [ Author::{
, name = "Xe Iaso"
, handle = "xe"
, picUrl = Some "/static/img/avatar.png"
, link = Some "https://christine.website"
, twitter = Some "theprincessxena"
, default = True
, inSystem = True
}
, Author::{
, name = "Jessie"
, handle = "Heartmender"
, picUrl = Some
"https://cdn.christine.website/file/christine-static/img/UPRcp1pO_400x400.jpg"
, twitter = Some "BeJustFine"
, inSystem = True
}
, Author::{
, name = "Ashe"
, handle = "ectamorphic"
, picUrl = Some
"https://cdn.christine.website/file/christine-static/img/FFVV1InX0AkDX3f_cropped_smol.jpg"
, inSystem = True
}
, Author::{ name = "Nicole", handle = "Twi", inSystem = True }
, Author::{ name = "Mai", handle = "Mai", inSystem = True }
, Author::{ name = "Sephira", handle = "Sephie", inSystem = True }
]

View File

@ -1,346 +0,0 @@
let xesite = ./types/package.dhall
let Job = xesite.Job
let Salary = xesite.Salary
let Stock = xesite.Stock
let StockKind = xesite.StockKind
let Company = xesite.Company
let Location = xesite.Location
let annual = \(rate : Natural) -> Salary::{ amount = rate }
let hourly = \(rate : Natural) -> Salary::{ amount = rate, per = "hour" }
let annualCAD = \(rate : Natural) -> Salary::{ amount = rate, currency = "CAD" }
let mercerIsland =
Location::{
, city = "Mercer Island"
, stateOrProvince = "WA"
, country = "USA"
}
let bellevue = mercerIsland // { city = "Bellevue" }
let mountainView =
Location::{
, city = "Mountain View"
, stateOrProvince = "CA"
, country = "USA"
, remote = False
}
let sf = mountainView // { city = "San Fransisco" }
let montreal =
Location::{
, city = "Montreal"
, stateOrProvince = "QC"
, country = "CAN"
, remote = False
}
let ottawa =
Location::{ city = "Ottawa", stateOrProvince = "ON", country = "CAN" }
let imvu =
Company::{
, name = "IMVU"
, url = Some "https://imvu.com"
, tagline =
"a company whose mission is to help people find and communicate with eachother. Their main product is a 3D avatar-based chat client and its surrounding infrastructure allowing creators to make content for the avatars to wear."
, location = mountainView // { city = "Redwood City" }
}
let tailscale =
Company::{
, name = "Tailscale"
, url = Some "https://tailscale.com"
, tagline =
"a zero config VPN for building secure networks. Install on any device in minutes. Remote access from any network or physical location."
, location = ottawa // { city = "Toronto" }
}
in [ Job::{
, company = Company::{
, name = "Symplicity"
, tagline =
"a company that provides students with the tools and connections they need to enhance their employability while preparing to succeed in today's job market."
, url = Some "https://www.symplicity.com"
, location = Location::{
, city = "Arlington"
, stateOrProvince = "VA"
, country = "USA"
, remote = False
}
}
, title = "Junior Systems Administrator"
, startDate = "2013-11-11"
, endDate = Some "2014-01-06"
, daysWorked = Some 56
, salary = annual 50000
, leaveReason = Some "terminated"
, locations =
[ Location::{
, city = "Arlington"
, stateOrProvince = "VA"
, country = "USA"
, remote = False
}
]
, highlights = [ "Python message queue processing" ]
, hideFromResume = True
}
, Job::{
, company = Company::{
, name = "OpDemand"
, defunct = True
, tagline =
"the company behind the open source project Deis, a distributed platform-as-a-service (PaaS) designed from the ground up to emulate Heroku but on privately owned servers."
, location = Location::{
, city = "Boulder"
, stateOrProvince = "CO"
, country = "USA"
}
}
, title = "Software Engineering Intern"
, startDate = "2014-07-14"
, endDate = Some "2014-08-27"
, daysWorked = Some 44
, daysBetween = Some 189
, salary = annual 35000
, leaveReason = Some "terminated"
, locations = [ mercerIsland ]
, highlights =
[ "Built new base image for Deis components"
, "Research and development on a new builder component"
]
, hideFromResume = True
}
, Job::{
, company = Company::{
, name = "Appen"
, url = Some "https://appen.com/"
, tagline =
"is a company that uses crowdsourcing to have its customers submit tasks to be done, similar to Amazon's Mechanical Turk."
, location = mountainView // { city = "San Francisco", remote = True }
}
, title = "Consultant"
, contract = True
, startDate = "2014-09-17"
, endDate = Some "2014-10-15"
, daysWorked = Some 28
, daysBetween = Some 21
, salary = hourly 90
, leaveReason = Some "contract not renewed"
, locations = [ mercerIsland ]
, highlights =
[ "Research and development on scalable Linux deployments on AWS via CoreOS and Docker"
, "Development of in-house tools to speed instance creation"
, "Laid groundwork on the creation and use of better tools for managing large clusters of CoreOS and Fleet machines"
]
}
, Job::{
, company = Company::{
, name = "VTCSecure"
, url = Some "https://www.vtcsecure.com/"
, tagline =
"a company dedicated to helping with custom and standard audio/video conferencing solutions. They specialize in helping the deaf and blind communicate over today's infrastructure without any trouble on their end."
, location = Location::{
, city = "Clearwater"
, stateOrProvince = "FL"
, country = "USA"
}
}
, title = "Consultant"
, contract = True
, startDate = "2014-10-27"
, endDate = Some "2015-02-09"
, daysWorked = Some 105
, daysBetween = Some 12
, salary = hourly 90
, leaveReason = Some "contract not renewed"
, locations = [ mercerIsland ]
, highlights =
[ "Started groundwork for a dynamically scalable infrastructure on a project for helping the blind see things"
, "Developed a prototype of a new website for VTCSecure"
, "Education on best practices using Docker and CoreOS"
, "Learning Freeswitch"
]
}
, Job::{
, company = imvu
, title = "Site Reliability Engineer"
, startDate = "2015-03-30"
, endDate = Some "2016-03-07"
, daysWorked = Some 343
, daysBetween = Some 49
, salary = annual 125000 // { stock = Some Stock::{ amount = 20000 } }
, leaveReason = Some "demoted"
, locations = [ mountainView ]
, highlights =
[ "Wrote up technical designs"
, "Implemented technical designs on an over 800 machine cluster"
, "Continuous learning of a lot of very powerful systems and improving upon them when it is needed"
]
}
, Job::{
, company = imvu
, title = "Systems Administrator"
, startDate = "2016-03-08"
, endDate = Some "2016-04-01"
, daysWorked = Some 24
, daysBetween = Some 1
, salary = annual 105000
, leaveReason = Some "quit"
, locations = [ mountainView // { city = "Redwood City" } ]
}
, Job::{
, company = Company::{
, name = "Pure Storage"
, url = Some "https://www.purestorage.com/"
, tagline =
"a Mountain View, California-based enterprise data flash storage company founded in 2009. It is traded on the NYSE (PSTG)."
, location = mountainView
}
, title = "Member of Technical Staff"
, startDate = "2016-04-04"
, endDate = Some "2016-08-03"
, daysWorked = Some 121
, daysBetween = Some 3
, salary =
annual 135000
// { stock = Some Stock::{
, amount = 5000
, liquid = True
, kind = StockKind.Grant
}
}
, leaveReason = Some "quit"
, locations = [ mountainView ]
, highlights = [ "Python 2 code maintenance", "Working with Foone" ]
}
, Job::{
, company = Company::{
, name = "Backplane.io"
, defunct = True
, location = sf
}
, title = "Software Engineer"
, startDate = "2016-08-24"
, endDate = Some "2016-11-22"
, daysWorked = Some 90
, daysBetween = Some 21
, salary = annual 105000 // { stock = Some Stock::{ amount = 85000 } }
, leaveReason = Some "terminated"
, locations = [ sf ]
, highlights =
[ "Performance monitoring of production servers"
, "Continuous deployment and development in Go"
, "Learning a lot about HTTP/2 and load balancing"
]
}
, Job::{
, company = Company::{
, name = "MBO Partners (Heroku)"
, tagline = "a staffing agency used to contract me for Heroku."
, location = Location::{
, city = "Herndon"
, stateOrProvince = "VA"
, country = "USA"
}
}
, title = "Consultant"
, contract = True
, startDate = "2017-02-13"
, endDate = Some "2017-11-13"
, daysWorked = Some 273
, daysBetween = Some 83
, salary = hourly 120
, leaveReason = Some "hired"
, locations = [ mountainView ]
}
, Job::{
, company = Company::{
, name = "Heroku"
, url = Some "https://heroku.com"
, tagline =
"a cloud Platform-as-a-Service (PaaS) that created the term 'platform as a service'. Heroku currently supports several programming languages that are commonly used on the web. Heroku, one of the first cloud platforms, has been in development since June 2007, when it supported only the Ruby programming language, but now supports Java, Node.js, Scala, Clojure, Python, PHP, and Go."
, location = sf
}
, title = "Senior Software Engineer"
, startDate = "2017-11-13"
, endDate = Some "2019-03-08"
, daysWorked = Some 480
, daysBetween = Some 0
, salary = annual 150000
, leaveReason = Some "quit"
, locations = [ mountainView, bellevue ]
, highlights =
[ "JVM Application Metrics"
, "Go Runtime Metrics Agent"
, "Other backend fixes and improvements on Threshold Autoscaling and Threshold Alerting"
, "Public-facing blogpost writing"
]
}
, Job::{
, company = Company::{
, name = "Lightspeed POS"
, url = Some "https://lightspeedhq.com"
, tagline =
"a provider of retail, ecommerce and point-of-sale solutions for small and medium scale businesses."
, location = montreal
}
, title = "Expert principal en fiabilité du site"
, startDate = "2019-05-06"
, endDate = Some "2020-11-27"
, daysWorked = Some 540
, daysBetween = Some 48
, salary =
annualCAD 115000
// { stock = Some Stock::{ amount = 7500, liquid = True } }
, leaveReason = Some "quit"
, locations = [ montreal ]
, highlights =
[ "Migration from cloud to cloud"
, "Work on the cloud platform initiative"
, "Crafting reliable infrastructure for clients of customers"
, "Creation of an internally consistent and extensible command line interface for internal tooling"
]
}
, Job::{
, company = tailscale
, title = "Software Designer"
, startDate = "2020-12-14"
, endDate = Some "2022-03-01"
, daysWorked = Some 442
, daysBetween = Some 0
, salary = annualCAD 135000
, leaveReason = Some "raise"
, locations = [ montreal // { remote = True }, ottawa ]
, highlights =
[ "Go programming"
, "SQL integrations"
, "Public-facing content writing"
, "Customer support"
]
}
, Job::{
, company = tailscale
, title = "Archmage of Infrastructure"
, startDate = "2022-03-01"
, salary = annualCAD 147150
, locations = [ ottawa ]
, highlights =
[ "The first developer relations person at Tailscale"
, "Public-facing content writing"
, "Public speaking"
, "Developing custom integration solutions and supporting them"
]
}
]

View File

@ -1,38 +0,0 @@
let xesite = ./types/package.dhall
let Resume = xesite.Resume
let Link = xesite.Link
in Resume::{
, hnLinks =
[ Link::{
, url = "https://news.ycombinator.com/item?id=29522941"
, title = "'Open Source' is Broken"
}
, Link::{
, url = "https://news.ycombinator.com/item?id=29167560"
, title = "The Surreal Horror of PAM"
}
, Link::{
, url = "https://news.ycombinator.com/item?id=27175960"
, title = "Systemd: The Good Parts"
}
, Link::{
, url = "https://news.ycombinator.com/item?id=26845355"
, title = "I Implemented /dev/printerfact in Rust"
}
, Link::{
, url = "https://news.ycombinator.com/item?id=25978511"
, title = "A Model for Identity in Software"
}
, Link::{
, url = "https://news.ycombinator.com/item?id=31390506"
, title = "Fly.io: The reclaimer of Heroku's magic"
}
, Link::{
, url = "https://news.ycombinator.com/item?id=31149801"
, title = "Crimes with Go Generics"
}
]
}

View File

@ -1,19 +0,0 @@
{ Type =
{ name : Text
, handle : Text
, picUrl : Optional Text
, link : Optional Text
, twitter : Optional Text
, default : Bool
, inSystem : Bool
}
, default =
{ name = ""
, handle = ""
, picUrl = None Text
, link = None Text
, twitter = None Text
, default = False
, inSystem = False
}
}

View File

@ -1,17 +0,0 @@
let Location = ./Location.dhall
in { Type =
{ name : Text
, url : Optional Text
, tagline : Text
, location : Location.Type
, defunct : Bool
}
, default =
{ name = ""
, url = None Text
, tagline = ""
, location = Location::{=}
, defunct = False
}
}

View File

@ -1,33 +0,0 @@
let Person = ./Person.dhall
let Author = ./Author.dhall
let Job = ./Job.dhall
let defaultPort = env:PORT ? 3030
let defaultWebMentionEndpoint =
env:WEBMENTION_ENDPOINT
? "https://mi.within.website/api/webmention/accept"
in { Type =
{ signalboost : List Person.Type
, authors : List Author.Type
, port : Natural
, clackSet : List Text
, resumeFname : Text
, webMentionEndpoint : Text
, miToken : Text
, jobHistory : List Job.Type
}
, default =
{ signalboost = [] : List Person.Type
, authors = [] : List Author.Type
, port = defaultPort
, clackSet = [ "Ashlynn" ]
, resumeFname = "./static/resume/resume.md"
, webMentionEndpoint = defaultWebMentionEndpoint
, miToken = "${env:MI_TOKEN as Text ? ""}"
, jobHistory = [] : List Job.Type
}
}

View File

@ -1,35 +0,0 @@
let Company = ./Company.dhall
let Salary = ./Salary.dhall
let Location = ./Location.dhall
in { Type =
{ company : Company.Type
, title : Text
, contract : Bool
, startDate : Text
, endDate : Optional Text
, daysWorked : Optional Natural
, daysBetween : Optional Natural
, salary : Salary.Type
, leaveReason : Optional Text
, locations : List Location.Type
, highlights : List Text
, hideFromResume : Bool
}
, default =
{ company = Company::{=}
, title = "Unknown"
, contract = False
, startDate = "0000-01-01"
, endDate = None Text
, daysWorked = None Natural
, daysBetween = None Natural
, salary = Salary::{=}
, leaveReason = None Text
, locations = [] : List Location.Type
, highlights = [] : List Text
, hideFromResume = False
}
}

View File

@ -1 +0,0 @@
{ Type = { url : Text, title : Text }, default = { url = "", title = "" } }

View File

@ -1,3 +0,0 @@
{ Type = { city : Text, stateOrProvince : Text, country : Text, remote : Bool }
, default = { remote = True, city = "", stateOrProvince = "", country = "CAN" }
}

View File

@ -1,9 +0,0 @@
{ Type =
{ name : Text
, tags : List Text
, gitLink : Optional Text
, twitter : Optional Text
}
, default =
{ name = "", tags = [] : List Text, gitLink = None Text, twitter = None Text }
}

View File

@ -1,21 +0,0 @@
let Location = ./Location.dhall
let Link = ./Link.dhall
in { Type =
{ name : Text
, tagline : Text
, location : Location.Type
, hnLinks : List Link.Type
}
, default =
{ name = "Xe Iaso"
, tagline = "Archmage of Infrastructure"
, location = Location::{
, city = "Ottawa"
, stateOrProvince = "ON"
, country = "CAN"
}
, hnLinks = [] : List Link.Type
}
}

View File

@ -1,11 +0,0 @@
let Stock = ./Stock.dhall
in { Type =
{ amount : Natural
, currency : Text
, per : Text
, stock : Optional Stock.Type
}
, default =
{ amount = 0, currency = "USD", per = "year", stock = None Stock.Type }
}

View File

@ -1,17 +0,0 @@
let StockKind = ./StockKind.dhall
in { Type =
{ kind : StockKind
, amount : Natural
, liquid : Bool
, vestingYears : Natural
, cliffYears : Natural
}
, default =
{ kind = StockKind.Options
, amount = 0
, liquid = False
, vestingYears = 4
, cliffYears = 1
}
}

View File

@ -1 +0,0 @@
< Grant | Options >

View File

@ -1,12 +0,0 @@
{ Author = ./Author.dhall
, Company = ./Company.dhall
, Config = ./Config.dhall
, Job = ./Job.dhall
, Link = ./Link.dhall
, Location = ./Location.dhall
, Person = ./Person.dhall
, Resume = ./Resume.dhall
, Salary = ./Salary.dhall
, Stock = ./Stock.dhall
, StockKind = ./StockKind.dhall
}

View File

@ -1,27 +0,0 @@
# JSON Feed Extensions
Here is the documentation of all of my JSON Feed extensions. I have created
these JSON Feed extensions in order to give users more metadata about my
articles and talks.
## `_xesite_frontmatter`
This extension is added to [JSON Feed
Items](https://www.jsonfeed.org/version/1.1/#items-a-name-items-a) and gives
readers a copy of the frontmatter data that I annotate my posts with. The
contents of this will vary by post, but will have any of the following fields:
* `about` (required, string) is a link to this documentation. It gives readers
of the JSON Feed information about what this extension does. This is for
informational purposes only and can safely be ignored by programs.
* `series` (optional, string) is the optional blogpost series name that this
item belongs to. When I post multiple posts about the same topic, I will
usually set the `series` to the same value so that it is more discoverable [on
my series index page](https://xeiaso.net/blog/series).
* `slides_link` (optional, string) is a link to the PDF containing the slides
for a given talk. This is always set on talks, but is technically optional
because not everything I do is a talk.
* `vod` (optional, string) is an object that describes where you can watch the
Video On Demand (vod) for the writing process of a post. This is an object
that always contains the fields `twitch` and `youtube`. These will be URLs to
the videos so that you can watch them on demand.

View File

@ -2,11 +2,11 @@
"nodes": {
"flake-utils": {
"locked": {
"lastModified": 1652776076,
"narHash": "sha256-gzTw/v1vj4dOVbpBSJX4J0DwUR6LIyXo7/SuuTJp1kM=",
"lastModified": 1649676176,
"narHash": "sha256-OWKJratjt2RW151VUlJPRALb7OU2S5s+f0vLj4o1bHM=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "04c1b180862888302ddfb2e3ad9eaa63afc60cf8",
"rev": "a4b154ebbdc88c8498a5c7b01589addc9e9cb678",
"type": "github"
},
"original": {
@ -20,11 +20,11 @@
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1652722411,
"narHash": "sha256-FxzNgYiH9c91hUVAntcjrqY//KOTUPP2a4e8Wyuysxg=",
"lastModified": 1650265945,
"narHash": "sha256-SO8+1db4jTOjnwP++29vVgImLIfETSXyoz0FuLkiikE=",
"owner": "nix-community",
"repo": "naersk",
"rev": "94beb7a3edfeb3bcda65fa3f2ebc48ec6b40bf72",
"rev": "e8f9f8d037774becd82fce2781e1abdb7836d7df",
"type": "github"
},
"original": {
@ -35,11 +35,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1653117584,
"narHash": "sha256-5uUrHeHBIaySBTrRExcCoW8fBBYVSDjDYDU5A6iOl+k=",
"lastModified": 1651114127,
"narHash": "sha256-/lLC0wkMZkAdA5e1W76SnJzbhfOGDvync3VRHJMtAKk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f4dfed73ee886b115a99e5b85fdfbeb683290d83",
"rev": "6766fb6503ae1ebebc2a9704c162b2aef351f921",
"type": "github"
},
"original": {
@ -49,11 +49,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1653060744,
"narHash": "sha256-kfRusllRumpt33J1hPV+CeCCylCXEU7e0gn2/cIM7cY=",
"lastModified": 1651007983,
"narHash": "sha256-GNay7yDPtLcRcKCNHldug85AhAvBpTtPEJWSSDYBw8U=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "dfd82985c273aac6eced03625f454b334daae2e8",
"rev": "e10da1c7f542515b609f8dfbcf788f3d85b14936",
"type": "github"
},
"original": {

Some files were not shown because too many files have changed in this diff Show More