<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>fun memory violations</title><link>/</link><description/><atom:link href="/rss.xml" rel="self"/><lastBuildDate>Fri, 24 Nov 2023 00:00:00 +0100</lastBuildDate><item><title>My first scifi short story</title><link>/blog/my-first-scifi-short-story</link><description>&lt;p&gt;You may not know this about me, but I've been writing a SciFi novel
for the better part of a decade now.  This year I (somewhat)
participated in &lt;a href="https://nanowrimo.org"&gt;NaNoWriMo&lt;/a&gt; to work on it.  The full story still
isn't nowhere complete.&lt;/p&gt;
&lt;p&gt;But when I sent some friends individual scenes for feedback (or just
to showcase the world and my writing style) someone suggested I should
consider publishing one of the chapters as a stand-alone short story.
And that's exactly what this is.&lt;/p&gt;
&lt;p&gt;So here you go!  I hope you enjoy this random bit of SciFi world
building.  Maybe I will publish other short stories like this in
future, but who knows.  Certainly in another 10 years the novel should
be done.  If you're an editor at a publisher and you like what you
read: call me, lol.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;The Royal Regatta&lt;/h2&gt;
&lt;p&gt;A holoscreen blared in a bar somewhere on Terminus 361.  It was
showing two presenters sitting at a desk, a vaguely masculine and a
vaguely feminine looking person, both of them wearing loud, bright
suits, having their puffy hair styled backwards, and wearing gold
glitter around their eyelashes and hairline.  Anyone only casually
looking at the cast, or viewing from a distance, would have had
trouble keeping the two figures apart.&lt;/p&gt;
&lt;p&gt;“That was quite the recap Mel,” the masc presenter commented.&lt;/p&gt;
&lt;p&gt;“Absolutely Mev, absolutely.  Coming up next, I am personally very
excited by the next position.  Team Alhama, from the Great
Westerland,” she turned over to Mev, “two time regional champion,
first time contender in the &lt;i&gt;Pandam&lt;/i&gt; regatta.”&lt;/p&gt;
&lt;p&gt;“They are certainly here to fight but the question is, whether their
pilot, someone who has only been racing needle ships for three years,
is up to the task.”&lt;/p&gt;
&lt;p&gt;“Oh yes, oh yes”&lt;/p&gt;
&lt;p&gt;“As everyone knows, that is not a long time to be behind the
proverbial stick of such a powerful engine.”&lt;/p&gt;
&lt;p&gt;“So who is this new pilot?”&lt;/p&gt;
&lt;p&gt;“Her name is Zhenzha Vae. And I think we have a clip of her.”&lt;/p&gt;
&lt;p&gt;The feed switched over to another flat view.  It showed a woman, maybe
in her early thirties, with deep black hair, braided into several
small locks, tied together with a fluffy hairband.  She had dark green
eyes and her skin was a medium brown, her mouth twisted into a narrow
smile, glaring at the camera.&lt;/p&gt;
&lt;p&gt;“I know we’re the underdogs in this season but believe me when I say,”
she paused for emphasis, “your &lt;i&gt;ostentatious&lt;/i&gt; engineers have
never seen what a real Westerland engine can do.”&lt;/p&gt;
&lt;p&gt;The view cut back, the femme presenter smirking.&lt;/p&gt;
&lt;p&gt;“She’s got grit, I’ll give her that. But she will have to convince me
with her flying, proper.”&lt;/p&gt;
&lt;p&gt;“Certainly Mel, certainly. But let’s go live to the preparation hall,
while Team Alhama is at this very moment getting their engine ready
for the pre-race checks.”&lt;/p&gt;
&lt;p&gt;Zhenzha looked disconnected on camera, like nobody was actually
watching her.  She interacted with her teammates, flicked through a
data tablet of flight parameters and coordinates, or simply leaned
against a bulky crate behind her as she focused on her breathing.
Finally it was time.  She was wearing a pitch black flight suit, she
shoved her braids into the back of her shirt and put a slim black
flight helmet on.  Her visor was tinted pink, yellow, and blue, the
colours of the Great Westerland flag.&lt;/p&gt;
&lt;p&gt;The needle ship was massive, reaching out from the holoscreen.  It was
at least two hundred metres long and twenty metres high and wide.
It’s form was simple: long straight lines, with low-angles, but
discrete edges.  It slowly sharpened into a tip towards the bow, and
had a wide aft plate, housing three sets of engine effectors: one ion
and two microwarp.&lt;/p&gt;
&lt;p&gt;The hull was made up of a black metal sheets, some of which had
sponsor decals, others technical specifications and maintenance
indicators printed on them.&lt;/p&gt;
&lt;p&gt;The ship was ejected from the hangar and hovered around the starting
area, keeping itself steady with the gravity engines to all sides.
It’s hull plating had started extending outwards slightly, revealing
rows and rows of measuring equipment boxes and additional thrusters.
Inside of it Zhenzha had hooked herself into a control matrix,
enveloping her arms and legs, providing reverse kinematics to her
movement.  A shimmering black cable was plugged into a socket at the
base of her neck, drooping down slightly as it arched upward into the
ceiling.  She smirked.  The whole ship started to hum.&lt;/p&gt;
&lt;p&gt;“And this is it, the countdown has started, the &lt;s&gt;Black Nebula&lt;/s&gt; —
wow, what a name by the way—“&lt;/p&gt;
&lt;p&gt;“Goosebumps!”&lt;/p&gt;
&lt;p&gt;“—has just started its priming sequence. Everyone brace yourselves.”&lt;/p&gt;
&lt;p&gt;“There are a lot of people who want to see this team, and in
particular this pilot, do well this season.”&lt;/p&gt;
&lt;p&gt;“Ten more seconds.”&lt;/p&gt;
&lt;p&gt;“We can certainly hope that this will be a successful start to their
first season here, at the seventy-seventh, legendary, sexennial Pandam
Royal Regatta !”&lt;/p&gt;
&lt;p&gt;The ship hummed louder, pulsing with energy, countless capacitors
charging, and fields subtly adjusting.&lt;/p&gt;
&lt;p&gt;“Five. Four. Three. Two. One.”&lt;/p&gt;
&lt;p&gt;The countdown hit zero and almost instantly the ship started growling.
The space in front of the &lt;em&gt;Black Nebula&lt;/em&gt; started to morph and warp out
of shape, swallowing the ship, at first slowly at the front, then the
rest disappeared with a brief flash of light, dragging a very faint
trail behind itself into the distance, barely visible on the holocast.
Almost instantly the gravitational waves could be felt around the
launch hangar, heard as a burst bass symphony.&lt;/p&gt;
&lt;p&gt;“And they are off, the &lt;s&gt;Black Nebula&lt;/s&gt;, with Zhenzha Vae at the
helm, racing for team Alhama of the Great Westerland. What is their
first Pandam regatta opening going to be?”&lt;/p&gt;
&lt;p&gt;“It would appear as if team Alhama is going for a reverse gravity turn
around Pheneus, running the system counter-clockwise.”&lt;/p&gt;
&lt;p&gt;“We have only seen this approach taken twice during the qualifiers, so
far. Mev, maybe you could give some insight into why this is
considered such a bold strategy this season.”&lt;/p&gt;
&lt;p&gt;“Certainly Mel,” a view of the solar system came up, with a small
window in the bottom right frame still showing the &lt;em&gt;Black Nebula&lt;/em&gt;,
severely warp shifted and distorted as it was visible from one of the
many thousand orbital cameras littered around the system, “this season
the orbital periods of Pheneus and Vhalstella, the Vhey system’s two
gas giants — for viewers across the Galactic expanse — are almost
directly opposite to each other, with the system core right in the
middle.&lt;/p&gt;
&lt;p&gt;“Approaching the system clockwise means that the Vhalstella checkpoint
can be used as a gravity boost into the lower systems—“&lt;/p&gt;
&lt;p&gt;“Free acceleration essentially.”&lt;/p&gt;
&lt;p&gt;“—free acceleration, quite right Mel.  Taking the counter-clockwise
route gives a small time advantage in the beginning, but Vhalstella’s
gravity is going to slow them down towards the end of the run.  We
will see if team Alhama can still keep their advantage.”&lt;/p&gt;
&lt;p&gt;“Oh and we are coming up on the first checkpoint…”&lt;/p&gt;
&lt;p&gt;Zhenzha had her eyes closed, but there was plenty for her to see.  Her
arms and legs were swaying in the control struts that were holding her
in place.  The stars were blurry messes around her, rows of numbers
were streaming down her peripheral vision.  She felt a soft breeze on
her face and her race engineer mumbling statistics in her ears, with
several seconds delay (she tried not to think about the exorbitant
logistics of providing a feed to her in this moment at all).&lt;/p&gt;
&lt;p&gt;The ship around her was humming and occasionally screaming and
whining.  The warp field emitters were stretched to their legal limits
as the &lt;em&gt;Black Nebula&lt;/em&gt; hurled itself across the Vhey system with
super-relativistic speeds.  She could feel the ebb and flow in the
gravity waves around her.&lt;/p&gt;
&lt;p&gt;“You’re coming up on the first checkpoint.  Time looks good.”&lt;/p&gt;
&lt;p&gt;Zhenzha tightened the gravity fields, releasing on acceleration and
putting the ship into a gentle spin to not lose stability.  For a
flash of a microsecond she felt something go past her, then it was
gone.  She widened the fields again and pushed the accelerator.  The
engine howled and she felt herself be pulled backwards in her control
harness.&lt;/p&gt;
&lt;p&gt;“Incredible, team Alhama bringing in the first checkpoint time of
34.2217 seconds, that is, Mel, I believe—“&lt;/p&gt;
&lt;p&gt;“Even after some compensation, this is the fastest time of this
qualifier, so far.”&lt;/p&gt;
&lt;p&gt;“Incredible.”&lt;/p&gt;
&lt;p&gt;Zhenzha kept pushing.&lt;/p&gt;
&lt;p&gt;“Kapo belt is coming up in 350 mk. And watch your port wake tails,
you’re dangerously close to the red line.”&lt;/p&gt;
&lt;p&gt;She nodded, mostly for herself, then reigned in some of her field
projectors, collapsing her gravity wake back to just under two million
kilometres, making the ship run slightly more bumpy.  Her view showed
a wall of object indicators coming towards her.  She kept pushing,
breaking through the 100 xc limit.  One of the team Minds had plotted
a path through the belt hours ago, but by now some of the rocks would
have drifted. She had to make adjustments to their route.&lt;/p&gt;
&lt;p&gt;The first rocks started hurling by her, too fast to register, to
briefly to appreciate how close an encounter it had already been.  The
twelve million kilometre thick Kapo belt was wrapping itself around
the core planets.&lt;/p&gt;
&lt;p&gt;“Mev!  Mev, it appears that Zhenzha Vae is not slowing down.”&lt;/p&gt;
&lt;p&gt;“It would appear so, Mel, it would appear so. Team Alhama seems to
have chosen a through-route for the Kapo belt.  But a belt transfer
requires significantly lower speeds and is usually deemed a bad
strategy.”&lt;/p&gt;
&lt;p&gt;Another three seconds had gone by and she had reached the edge of the
belt.  The needle ship had flattened its gravity fields from several
million kilometres down to just a few ten thousand metres.  It was as
if the engine itself was rebelling against her choice of manoeuvre,
but she didn’t care.&lt;/p&gt;
&lt;p&gt;“Check projector 77-b, it looks like it’s spitting out bad metrics.”&lt;/p&gt;
&lt;p&gt;She checked the projector and indeed it seemed to be slightly off.
But not enough to do anything about it, and anyway, she was too busy.&lt;/p&gt;
&lt;p&gt;She was deep within the belt at this point, flicking the ship back and
forth to narrowly evade a collision, scraping by another rock close
enough to physically touch it.  The &lt;em&gt;Black Nebula&lt;/em&gt; was in a mild spin,
it’s gravity wake flaring wildly behind the ship.  With every twist and
turn Zhenzha made to adjust her trajectory another few rocks ten
thousand metres off her bow were torn to pieces by the gravity forces
spiking at the edges of the warp bubble.&lt;/p&gt;
&lt;p&gt;“Half way through.”&lt;/p&gt;
&lt;p&gt;Zhenzha was in a trance, unable to even register new messages that
were coming in, her time, her position, it didn’t matter.  She was
surrounded by a sea of proximity alerts, surfing through the asteroid
belt and weaving and in and out of available pockets of safety.&lt;/p&gt;
&lt;p&gt;Finally, she reached the other side and accelerated again, maybe even
more aggressively than before.&lt;/p&gt;
&lt;p&gt;“Mel, I am at a loss of words.”&lt;/p&gt;
&lt;p&gt;“Me too Mev, me too.”&lt;/p&gt;
&lt;p&gt;“Dear viewers, we seem to be witnessing the making of a new record
time here, at the seventy-seventh &lt;u&gt;legendary&lt;/u&gt; sexennial Royal
Regatta.  Zhenzha Vae of team Alhama of Great Westerland, has just
crossed the Kapo belt in just 15.838 seconds.  We will have these
numbers verified, and I’m sure the referees are already checking the
flight footage and statistics.”&lt;/p&gt;
&lt;p&gt;“I suppose this shows us that even a belt transit is a valid strategy
if you don’t plan on slowing down for it.”&lt;/p&gt;
&lt;p&gt;Mev chuckled. “It would appear so, it would appear so.”&lt;/p&gt;
&lt;p&gt;The next stretch was easy.  Zhenzha hit the accelerator and curved
around the mid system to the Dhereliq (the old sandy mining colony)
checkpoint, almost forgetting to collapse her wake (ripping a
checkpoint gate apart was grounds for disqualification), using the
gravity assist to loop around the desert planet once and hitting
another checkpoint gate around its seventh moon, then plunging deeper
into the system and crossing the inner belt.  It was significantly
less dense and it became evident that it had been extensively mined
for almost a thousand years.&lt;/p&gt;
&lt;p&gt;“Another extravagant transit of the Sen belt. Team Alhama has
certainly come here to provide a show.”&lt;/p&gt;
&lt;p&gt;“They are succeeding. We have times on sections three and four at
11.8945, and 3.8141 seconds.”&lt;/p&gt;
&lt;p&gt;“Wow. Really. 3.8141. Wow.”&lt;/p&gt;
&lt;p&gt;“I think in all my time presenting I have not seen a sub-four for the
Dhereliq checkpoint pair.  Absolutely incredible.”&lt;/p&gt;
&lt;p&gt;“Incredible.”&lt;/p&gt;
&lt;p&gt;Zhenzha had to slow down for the inner system checkpoints.  The Vhey
star’s gravity was too strong and wake field requirements were much
stricter.&lt;/p&gt;
&lt;p&gt;Fucking civilian traffic.&lt;/p&gt;
&lt;p&gt;She hit the gate around Aquel’qu, then a few seconds later another
gate around Pandam’s moon.&lt;/p&gt;
&lt;p&gt;“Kapo coming up in 300 mk.”&lt;/p&gt;
&lt;p&gt;Zhenzha steadied her breathing and pushed the &lt;em&gt;Black Nebula&lt;/em&gt; forward.
She was floating in a sea of darkness, surrounded by data, flashes of
information, and proximity alerts coming up in front of her.  Her mind
was razor sharp, absorbed in total flow state as she dodged through
the Kapo belt once again, pushing harder this time.  Twice she almost
collided with a rock, only to make a last microsecond adjustment to
avoid disaster.  A kilometre to her right an asteroid was ripped apart
by a gravity wave spike.&lt;/p&gt;
&lt;p&gt;She was through it again, making her final approach to Vhalstella.&lt;/p&gt;
&lt;p&gt;“You know the drill.  Tight field, use the third spiral fractal.  Stay
strong.  Good luck.”&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;Black Nebula&lt;/em&gt; was approaching Terminus 222, located on
Vhalstella’s 22nd moon.  Under normal circumstances she would have to
make a gravity turn around the gas giant, shedding an incredible
amount of speed, then curving back to hit the inner gate in low orbit
around the giant itself, before accelerating for the final section.
But these were not ordinary circumstances, and the &lt;em&gt;Black Nebula&lt;/em&gt; was
no ordinary ship.&lt;/p&gt;
&lt;p&gt;Zhenzha banked hard towards the moon she had just shot past.  It felt
like she took another breath, then fully collapsed her outer gravity
fields, while letting the projectors facing the moon cycle through a
complex set of spiral fractals.  A screaming filled the air around
her, then a series of loud bangs cracked through the ship hull.  The
engine itself felt as if it was sputtering.&lt;/p&gt;
&lt;p&gt;The needle ship curved itself around the moon at an unnatural rate, as
if the laws of physics had gone completely out the window, as if the
little moon possessed the gravitational pull of a small star.  The
ship was being shaken through violently, creaking and moaning under
the load. The next five seconds felt like an eternity to her.  Zhenzha
could feel her pulse, throbbing in her neck, her breathing went stiff,
her muscles started aching.&lt;/p&gt;
&lt;p&gt;Finally she had made it. She reset the field arrangement back to a
default layout, collapsed them briefly for the checkpoint gate, then
opened up all engines, widened her warp field as much as was legal and
pushed.&lt;/p&gt;
&lt;p&gt;“I do not believe my eyes, dear viewers, what we are seeing here...”&lt;/p&gt;
&lt;p&gt;“Team Alhama managed to run the Vhalstella gate pair in just 7.5184
seconds! Please correct me if I’m wrong—“&lt;/p&gt;
&lt;p&gt;“That is certainly a new record time as well.”&lt;/p&gt;
&lt;p&gt;“Incredible. Approaching the gate in reverse—“&lt;/p&gt;
&lt;p&gt;“Something that team Alhama seems hellbent on demonstrating this
season, their ability to flip the rules upside down and get something
incredible from it.”&lt;/p&gt;
&lt;p&gt;“Does this mean Vhalstella’s gravity is not going to slow down them
down?”&lt;/p&gt;
&lt;p&gt;“Oh indeed, on the contrary. The way that team Alhama is going around
the giant now is even going to boost their speed.”&lt;/p&gt;
&lt;p&gt;“Incredible.”&lt;/p&gt;
&lt;p&gt;Zhenzha left out a breath of relief when she was on final approach.
She took off a few limiters and pushed the engine to its absolute
limit.  Her vision went blurry; even the inertia stabilisation she was
under could not save her from the acceleration forces now.  The engine
had started growling angrily, as if complaining about the load it was
under, in tonal intervals of five, from the lowest to the highest
possible audible note.  She broke the 300 xc barrier.  The &lt;em&gt;Black
Nebula&lt;/em&gt; curved around the system, along the outer edge of the Kapo
belt, crossing the entire length of the Vhey system in just a few
seconds.  Zhenzha started getting dizzy when the gas giant Pheneus was
coming towards her view, faster and faster, filling it out.  For a
microsecond she collapsed her fields to not rip the final gate to
pieces, then she cut the accelerator and rode her gravity wave around
Pheneus twice, three of its moons that happened to line up in a nice
formation for her to circle, then braking hard and coming to a stop
near her Terminus 361 team hangar.&lt;/p&gt;
&lt;p&gt;They had set a new qualifying record.  Back in the hangar she was
greeted by camera crews and reporters, the steaming hot needle ship
sitting on its four hydraulic legs behind her, and in front of her a
raging deck full of engineers, technicians, backup pilots, managers,
cooks, janitors, and anyone else who helped run team Alhama that day.
She pulled off her helmet, revealing her face and hair drenched in
sweat.  She was smiling, and waving at people who waved at her.  She
answered some questions about her flying, about the paths she took,
about the strategy that went into the run.  She thanked her teams
engineers, technicians, and strategy Minds.  She made sure to stress
that this was not the end of the regatta, that the main field was a
very different competition, but that they were honoured and excited to
have made such a splash at their first qualifying and that she was
excited to see where else they could go.&lt;/p&gt;
&lt;p&gt;She removed herself from the crowd by disappearing into a hatch
somewhere towards the back of the hangar.  Back in her room she
stripped off her flight suit, took a quick shower, then collapsed into
bed and slept.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;Edit 3.3.2024&lt;/h4&gt;
&lt;p&gt;Remove opening dialog on the holoscreen broadcast. Reworded some
sentences to be more direct.&lt;/p&gt;
&lt;p&gt;Cleaned up formatting, and switched from underline to italics, and
italics to bold.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Fri, 24 Nov 2023 00:00:00 +0100</pubDate><guid>tag:None,2023-11-24:/blog/my-first-scifi-short-story</guid><category>Blog</category><category>writing</category><category>scifi</category><category>nanowrimo</category></item><item><title>I am no longer using flakes</title><link>/blog/i-am-no-longer-using-flakes</link><description>&lt;p&gt;Before I really get started on what bothered me about flakes, I would
like to very clearly point out that this is my opinion, and also that
I am a big dumb-ass.&lt;/p&gt;
&lt;p&gt;I use my computer for lots of different creative and professional
(sometimes both) endeavour, and while I like Nix in a lot of ways (I
have even really come to love the syntax of the language), having
"managing my computer" as a hobby is not one of them.&lt;/p&gt;
&lt;p&gt;I deliberated whether I should write and publish this blog post, but
decided that I still wanted to share my experience and frustrations.
Maybe the way that I have come to use Nix on my computers is not in
line with "how you're supposed to do it", but maybe that's exactly the
reason why I should write &lt;em&gt;something&lt;/em&gt; about this topic.&lt;/p&gt;
&lt;p&gt;Anyway...&lt;/p&gt;
&lt;h2&gt;What are flakes&lt;/h2&gt;
&lt;p&gt;Back in 2019 &lt;a href="https://github.com/nixos/rfcs/pull/49"&gt;RFC 0049&lt;/a&gt; was proposed, which introduced the Nix
community to the new concept of "flakes", a way to manage Nix build
inputs and outputs in a pure and reproducible manner.  This made a lot
of people very angry and after months of &lt;em&gt;reasonable online
discourse&lt;/em&gt;, the RFC was withdrawn and implementation work began in the
new Nix CLIs behind an "experimental" feature flag.  This was done in
order to work on the design of flakes, and being able to explore
problems that came up more organically.  I can see however how people
might feel that the design was rejected, and was then snuck in the
backdoor by the RFC authors.  In the meantime a number of smaller RFCs
have come up by community members as a way to voice feature requests
for flakes.&lt;/p&gt;
&lt;p&gt;Responses to flakes are still varied to this day.  Some are really
into the features they enable your builds to have, and I have to admit
that being able to have a single &lt;code&gt;flake.nix&lt;/code&gt; file in a project
repository, which pins a version of nixpkgs and produces a build of
the given application is very nice.&lt;/p&gt;
&lt;p&gt;Disdain for even the idea of flakes can still be found in some corners
of the Internet however, and I think everyone involved in the
development of flakes is rightfully on-edge, given the amount of
hostility and abuse that they have been getting for &lt;em&gt;checks notes&lt;/em&gt;
implementing a new feature in a package manager.&lt;/p&gt;
&lt;p&gt;I am aware of this history and I don't want this blog post to become a
weapon wielded by jackasses to harass a bunch of people online.  Don't
be a dick and go look at some ducks instead.&lt;/p&gt;
&lt;h2&gt;What I did before&lt;/h2&gt;
&lt;p&gt;When I got started using NixOS I began by maintaining a nixpkgs
subtree.  That's what all my friends were doing, and it seemed like a
neat idea at the time.  I &lt;em&gt;was&lt;/em&gt; occasionally working on upstream
nixpkgs, so having all the code right there seemed like a sensible
idea.  In hindsight, it really wasn't, and it turned into a frequent
source of frustration (see the disclaimer above about how I don't want
"managing my computer" to be a hobby of mine).&lt;/p&gt;
&lt;p&gt;I stuck with this system for close to 4 years anyway (see the
disclaimer about being a dumb-ass), because the cost of migrating
always seemed to high.  I knew I wanted to try out flakes, but the
barrier to entry &lt;em&gt;also&lt;/em&gt; seemed too high.  The fact that the flakes RFC
was withdrawn and development continued behind an experimental feature
flag signalled, at least to me, a state of flux and uncertainty about
the design of flakes.  The fact that the only documentation available
was one short page on the (generally excellent, please contribute more
to it!) &lt;a href="https://nixos.wiki/wiki/flakes"&gt;NixOS wiki&lt;/a&gt;, and a blog post series by &lt;a href="https://www.tweag.io/blog/2020-05-25-flakes/"&gt;tweag&lt;/a&gt; didn't help
this.&lt;/p&gt;
&lt;p&gt;The two big problems with the nixpkgs-subtree approach are: nixpkgs is
huge and is going to make your computer unbearably slow, and
unmanageable merge conflicts in case I ever updated a computer and
didn't &lt;em&gt;immediately&lt;/em&gt; push the update to the repository remote.&lt;/p&gt;
&lt;p&gt;And while it would seem like something that is easy to avoid, I ran
into this problem again and again and again, to the point where by the
end my servers and desktops were running completely disjointed
configuration repositories, that only occasionally were updated by
sending patches around.  Fucking yikes.  Yes, this is my fault, but
the system I had designed myself into encouraged these sorts of human
errors to accumulate.&lt;/p&gt;
&lt;p&gt;Finally, late last year (2022) I started a job where I came into
&lt;em&gt;much&lt;/em&gt; closer contact with flakes, and so, I pulled off the
several-year-old band-aid and dove right into it.&lt;/p&gt;
&lt;h2&gt;Migrating to flakes&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://cyberchaos.dev/kookie/nomicon/-/commit/785366e86a475c56a6573c6c8781e03b4d60d216"&gt;This&lt;/a&gt; was the state that I inherited and moved over to
flakes.  It took me a few weeks to get things building again on my
NixOS desktop and Pop_OS (with home-manager) laptop.  Right off the
bat I didn't like a few things.  I was using the &lt;code&gt;NIX_PATH&lt;/code&gt; as a path
lookup for modules in my configuration, so I didn't have to rely on
relative paths between modules (I would frequently expand
&lt;code&gt;&amp;lt;configuration/foo&amp;gt;&lt;/code&gt; and similar lookups).  This isn't allowed with
flakes, unless you opt into impure evaluation mode, which is what I
did.  In hindsight, the way that my flakes configuration ended up
looking was &lt;em&gt;much&lt;/em&gt; more linear than the kludge of horror I had built
before, and so this limitation was &lt;em&gt;less&lt;/em&gt; of an issue, although it
still bothered me in some places.&lt;/p&gt;
&lt;p&gt;I also &lt;em&gt;really&lt;/em&gt; wasn't, and still am not a fan of the build syntax:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Before: &lt;code&gt;nix-build '&amp;lt;nixpkgs/nixos&amp;gt;' system -I nixos-config="$HOST"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;After: &lt;code&gt;nix build .#nixosConfiguration."$HOST".config.system.build.toplevel&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://cyberchaos.dev/kookie/nomicon/-/commit/8307e462f53290b53cf6ba1cec5272389cc705db"&gt;This&lt;/a&gt; is the commit that ported my desktop over to
flakes, if you wanna have a look.  In my build harness I removed a
bunch of features like being able to quickly build &lt;code&gt;vm&lt;/code&gt; and &lt;code&gt;iso&lt;/code&gt;
targets.  This might still be possible with flakes, but I didn't find
an obvious way to do things in the moment, and so I opted for removing
the features in the meantime.&lt;/p&gt;
&lt;p&gt;The NixOS documentation (and SEO!)  situation is bad enough, and
restricting yourself to results that talk about a subset of the
language and ecosystem made it unbearable in some cases to understand
what I was supposed to do.  I ended up reading several people's
configurations to copy things from them.&lt;/p&gt;
&lt;p&gt;I ended up with this custom harness function to create a NixOS system
because I hate code duplication (and a similar one for the
&lt;code&gt;homeManagerConfiguration&lt;/code&gt; function):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;nixosSystem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; root&lt;span class="p"&gt;:&lt;/span&gt; nixpkgs&lt;span class="o"&gt;.&lt;/span&gt;lib&lt;span class="o"&gt;.&lt;/span&gt;nixosSystem &lt;span class="p"&gt;(&lt;/span&gt;root &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;inherit&lt;/span&gt; system&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="ss"&gt;modules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; root&lt;span class="o"&gt;.&lt;/span&gt;modules &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        nix&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;nixPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="s2"&gt;&amp;quot;nixpkgs=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;nixpkgs&lt;span class="o"&gt;.&lt;/span&gt;outPath&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
          &lt;span class="s2"&gt;&amp;quot;home-manager=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;home-manager&lt;span class="o"&gt;.&lt;/span&gt;outPath&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
        nixpkgs&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;overlays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; defaultOverlays&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;

      &lt;span class="c1"&gt;## Include the home-manager NixOS module&lt;/span&gt;
      home-manager&lt;span class="o"&gt;.&lt;/span&gt;nixosModules&lt;span class="o"&gt;.&lt;/span&gt;home-manager
    &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It was important to me to have the &lt;code&gt;nixpkgs&lt;/code&gt; and &lt;code&gt;home-manager&lt;/code&gt; keys
set correctly in my &lt;code&gt;NIX_PATH&lt;/code&gt; for the "legacy" CLIs to be able to
pick them up and use.  Nonetheless, this caused countless issues that
I still don't fully understand.  But more on that in a little bit.&lt;/p&gt;
&lt;p&gt;Another rift I saw in the community of flakes users was whether or not
to use &lt;a href="https://github.com/numtide/flake-utils"&gt;&lt;code&gt;flake-utils&lt;/code&gt;&lt;/a&gt;.  The two philosophies seem to be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;"use flake-utils because it makes your life easier"&lt;/li&gt;
&lt;li&gt;"don't use flake-utils because it makes flakes seem too complex"&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which one is it?  Are they both true?  I ended up not including
another dependency for my configuration, instead writing the wrapper
functions myself (as I said, I really quite like writing Nix code!).&lt;/p&gt;
&lt;p&gt;Especially because all my computers are &lt;code&gt;x86_64-linux&lt;/code&gt;, and
&lt;code&gt;flake-utils&lt;/code&gt; is often used to work around some issues with flakes
regarding cross compilation.  Depending on what systems you use with
Nix, flake-utils may give you a better bang for your buck because you
need to write less obscure loop code that includes your configuration
root for multiple system targets.&lt;/p&gt;
&lt;p&gt;I imagine this will confuse potential adopters of flakes similarly to
how it confused me, and it certainly didn't leave me feeling rosy
about this technology I had just built my sand castle atop of.  If
you're interested in the custom wrapper code I wrote: here are my
&lt;a href="https://cyberchaos.dev/kookie/nomicon/-/blob/7086aea92808413968b7d67ba8dcd1537c309836/nixfiles/lib/default.nix"&gt;main utilities&lt;/a&gt; and &lt;a href="https://cyberchaos.dev/kookie/nomicon/-/blob/7086aea92808413968b7d67ba8dcd1537c309836/nixfiles/lib/users.nix"&gt;user utilities&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;Using flakes&lt;/h2&gt;
&lt;p&gt;And so, that was my life for about 6 months.  I would occasionally run
&lt;code&gt;nix flake update&lt;/code&gt;, which was easy to complete, almost never caused
any merge conflicts due to my dumbassery (and even the one or two
times it did, was easy enough to fix by just deleting the lockfile),
and life was good.&lt;/p&gt;
&lt;p&gt;I also started using flakes for some one-off projects, where I was
collaborating with other people (for example &lt;a href="https://gitlab.com/IGBC/jackctl/-/blob/b21e339aa4733130ed68da4285d4086a66871b49/flake.nix"&gt;jackctl&lt;/a&gt;, which you
should check out if you make music on Linux), where using flakes made
it easy to depend on multiple sources of nix code, and build a single
package with a particular postFixup phase or whatever.  I will still
use flakes for these use-cases, because I think they're the ideal
situation to map a simple set of inputs to a simple set of outputs.&lt;/p&gt;
&lt;p&gt;Importantly, this is &lt;em&gt;not&lt;/em&gt; my development environment, but rather
something that would be invoked in CI.&lt;/p&gt;
&lt;p&gt;But, I slowly noticed that the development environments littered
around my system stopped getting current &lt;code&gt;rustc&lt;/code&gt; packages.  The way I
build those is with &lt;code&gt;shell.nix&lt;/code&gt; files, which include &lt;code&gt;&amp;lt;nixpkgs&amp;gt;&lt;/code&gt; from
my path, which are built by the &lt;code&gt;lorri&lt;/code&gt; service.  The idea of having
different environments, that all pull from the same local package set
is just to reduce the space requirements on my computer.  I have a big
SSD, but might as well not pull in 50 slightly different versions of
&lt;code&gt;rustc&lt;/code&gt;, &lt;code&gt;cargo&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;At first I didn't really care, but with a lot of Rust projects
recently dropping down their supported Rust compiler period, I started
running into compilation issues.  I even &lt;a href="https://octodon.social/@spacekookie/110452765811294704"&gt;briefly installed
&lt;code&gt;rustup&lt;/code&gt;&lt;/a&gt; on my laptop because I was blocked from working on a
project and it was the easiest way to get out of my
pickle. &lt;em&gt;shudders&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I knew something had to change.  I couldn't go back to the way things
were before, and the way flakes made me re-evaluate my configuration
was &lt;strong&gt;good&lt;/strong&gt;.  At the same time, my computer started accumulating
strange behaviours I didn't really understand.  And maybe it was a
matter of not using the new CLIs exclusively, or wanting to rely on
&lt;code&gt;lorri&lt;/code&gt; to asynchronously build environments for me and injecting them
with direnv (something that works very well with emacs too).&lt;/p&gt;
&lt;p&gt;The last straw was a build failure as a result of an &lt;a href="https://github.com/nix-community/home-manager/issues/4035"&gt;incompatibility&lt;/a&gt;
between home-manager and nixpkgs, that had allegedly been fixed, but
updating both my nixpkgs and home-manager inputs over the span of 2
weeks didn't allow me to update my computer.  Maybe I got &lt;em&gt;extremely&lt;/em&gt;
unlucky with the unstable channel progressing, but in the end it
didn't really matter.  I wanted to make a change.&lt;/p&gt;
&lt;h2&gt;What now&lt;/h2&gt;
&lt;p&gt;I had previously evaluated different strategies for managing my
nixpkgs and home-manager dependencies.  I briefly thought about
subtrees, where I squash committed everything but decided that I didn't
really get &lt;em&gt;any&lt;/em&gt; benefit out of that arrangement.  I tried a
submodule, which was somehow even worse, and then I tried [&lt;code&gt;niv&lt;/code&gt;] and
flakes.  In the end, flakes briefly won out because I wanted to try
them.  So moving to &lt;code&gt;niv&lt;/code&gt; was the obvious choice.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;niv&lt;/code&gt; was born out of some of the ideas of the initial flakes RFC,
taking basically only its input management, encoded in a json
configuration, which gets parsed by some magic nix code (which I have
to admit, I do not fully understand, nor have I had to look at it
because something was broken or unclear as to how it worked).&lt;/p&gt;
&lt;p&gt;My build harness script looks like this now (the relevant bit):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;NIXPKGS_ALLOW_UNFREE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;home-manager&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$ROOT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;-I&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;nixpkgs=&lt;/span&gt;&lt;span class="nv"&gt;$DIR&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;-I&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;klib=&lt;/span&gt;&lt;span class="nv"&gt;$DIR&lt;/span&gt;&lt;span class="s2"&gt;/lib&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;-I&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;nixpkgs-overlays=&lt;/span&gt;&lt;span class="nv"&gt;$DIR&lt;/span&gt;&lt;span class="s2"&gt;/overlays&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;-I&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;home-manager=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$DIR&lt;/span&gt;/lib/find-component.sh&lt;span class="w"&gt; &lt;/span&gt;home-manager&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and the way I import nixpkgs looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; overlays &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt; args&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt;
  &lt;span class="ss"&gt;sources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="l"&gt;nix/sources.nix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="nb"&gt;import&lt;/span&gt; sources&lt;span class="o"&gt;.&lt;/span&gt;nixpkgs &lt;span class="p"&gt;(&lt;/span&gt;args &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;overlays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="l"&gt;lib/overlays.nix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; overlays&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I had to write a small utility for setting the appropriate NIX_PATH
for home-manager:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# De-reference current directory and grab the component parameter&lt;/span&gt;
&lt;span class="c1"&gt;# This will break if none was provided so... don&amp;#39;t do that :)&lt;/span&gt;
&lt;span class="nv"&gt;DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;realpath&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;dirname&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/..&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;COMPONENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;

&lt;span class="c1"&gt;# Run nix eval and just return the result&lt;/span&gt;
nix&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--expr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;(import &lt;/span&gt;&lt;span class="nv"&gt;$DIR&lt;/span&gt;&lt;span class="s2"&gt;/nix/sources.nix).&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;COMPONENT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.outPath&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--impure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tr&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;quot;&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The nice thing about grabbing the component paths from the niv sources
is that the &lt;code&gt;NIX_PATH&lt;/code&gt; environment variable gets populated with
absolute &lt;code&gt;/nix/store&lt;/code&gt; paths.  This means that changing something in my
configuration won't apply to things on my system until I next build
and switch to a new generation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt; ❤  (tempest) ~/sys&amp;gt; echo $NIX_PATH
nixpkgs=/nix/store/7znqbsc1vqyjhcmdvfjrfp73hhvazpwq-nixfiles 
home-manager=/nix/store/0haa6si3qmp8r80irj4a692qvxp51rfh-zb3bip08c8w6jxbhbmb4i852lp4a3d95-home-manager-src
nixpkgs-overlays=/nix/store/q015fg370v3qjwrz840pl5f38km4j5sh-overlays
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;In conclusion&lt;/h2&gt;
&lt;p&gt;In the end... is this better?  I really don't know.&lt;/p&gt;
&lt;p&gt;Flakes felt like magic in a lot of places, even though their
functionality should be able to be encoded into a simple &lt;code&gt;input -&amp;gt;
output&lt;/code&gt; relationship.  While using flakes I didn't feel like I
understood what my computer was doing.  And while my current solution
technically allowed me to reduce the amount of code needed for my
system to build, my solution is bespoke, and I can understand that
someone who hasn't thought about their Nix setup as long and hard as I
have, might feel overwhelmed by it.  This is especially a problem if
everyone comes up with slightly different variations on how they would
like to initialise their nixpkgs builds.  And maybe I should just have
globally installed &lt;code&gt;rustc&lt;/code&gt; and &lt;code&gt;cargo&lt;/code&gt; and called it a day.&lt;/p&gt;
&lt;p&gt;Shit... maybe managing my computer &lt;em&gt;is&lt;/em&gt; my hobby.&lt;/p&gt;
&lt;p&gt;I can certainly see how flakes can work for many, many people, and I
am probably in the minority of users who will bump into problems.&lt;/p&gt;
&lt;p&gt;At the same time, I'm not a fan of the way flakes have been developed.&lt;/p&gt;
&lt;p&gt;There seem to be a sentiment that flakes are "done", even though
they've technically never left the experimental stage.  I do not
condone the abuse directed towards the creators of this technology!
But at the same time, I can see why some people might feel annoyed at
the idea that an RFC was de facto rejected (withdrawing an RFC is not
generally done because its initial design was perfect), and then
having its feature set snuck into the Nix codebase without going
through the same RFC process again.  At this point, enough users
depend on the experimental flakes feature as it exists, it could be
argued that any breaking change would be too disruptive, and so the
current state &lt;em&gt;must&lt;/em&gt; be stabilised as is.&lt;/p&gt;
&lt;p&gt;&lt;ins&gt;I have also seen and felt the pressure of coming up with
perfectly measured criticism against flakes (one of the reasons, why I
was unsure about publishing this blog post), because of the way
conversations about them often divolve into abusive tirades.  No it's
not OK for people to be behaving the way they have been.  But it's
also not OK for the flake developers to dismiss people's criticism,
concearns, problems on the basis of some people being dicks.&lt;/ins&gt;&lt;/p&gt;
&lt;p&gt;Since 2019 the documentation situation for flakes has only improved
marginally.  There are a few more resources out there now, but none
are "official" or built by the community, and also none that go beyond
the basics of what a flake is and does (yes &lt;code&gt;nix shell&lt;/code&gt; is cool, but
&lt;code&gt;nix-shell&lt;/code&gt; existed before too).  There is a kind of chicken &amp;amp; egg
problem where documentation must refer to things that are stable, and
flakes need documentation to get more people into the headspace to try
to use them.&lt;/p&gt;
&lt;p&gt;Ultimately, I'm open to the idea of using flakes again.  Updating my
horrible hacks from before flakes to flakes was hard, changing from
flakes to niv was two afternoons.  So maybe I will try them again at
some point.  But for the time being, I decided it's more trouble to me
than it's worth.&lt;/p&gt;
&lt;p&gt;Thank you for reading this rambly post until the end.  Maybe you
learned something, or were able to contextualise some of your own
experiences or problems.  Please don't be a dick.  In the end, it
doesn't really matter.  Computers don't matter, and you shouldn't get
too upset about them.&lt;/p&gt;
&lt;p&gt;Cheers.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Sun, 18 Jun 2023 00:00:00 +0200</pubDate><guid>tag:None,2023-06-18:/blog/i-am-no-longer-using-flakes</guid><category>Blog</category><category>tech</category><category>nixos</category></item><item><title>Why I deleted my Twitter, and why maybe you should too</title><link>/blog/why-i-deleted-my-twitter-and-why-maybe-you-should-too</link><description>&lt;p&gt;I deleted my Twitter account this month.  It was a decision that I had
struggled with for months (if not years), and one that I want to talk
about.  This article is a collection of thoughts gathered through
conversations with friends on this topic.  I was advised to turn these
thoughts into a blog post.&lt;/p&gt;
&lt;p&gt;If you are struggling with your relationship to social media and
having a hard time cutting ties with some platform (in particular
Twitter), maybe this blog post will be helpful to you.&lt;/p&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;I got addicted to Twitter in the run-up to the 2016 US election.  I
was going through a bit of a moderate phase back then (sandwiched
between the punk days of my teens and the anarchy of today) and I
became part of "liberal twitter", consumed liberal memes, and enjoyed
dunking on conservatives.  Of course I didn't think Trump would win.&lt;/p&gt;
&lt;p&gt;After the election results this behaviour intensified.  I sought
refuge from the world that had shattered my understanding of society
by sliding deeper into the filter bubble that had sheltered me from
reality in the first place.  And so I revelled in making fun of Trump
and his supporters, celebrating the "covfefe" and body shaming, and
intensively following the discourse™.  Of course it didn't make me any
less miserable.&lt;/p&gt;
&lt;p&gt;The band-aid for the pain that I felt, the realisation that the world
didn't work the way I had swindled myself into believing, soon didn't
satisfy my need for comfort and so I became more dependent on instant
gratification through social media.  &lt;em&gt;I was unable to truly comprehend
the extent to which I was addicted to the thing that was hurting me.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Doom scrolling&lt;/em&gt; is a well known phenomenon in our terminally online
society and we talk about it as if it was unavoidable.  As if it was
an individualist problem.  We &lt;em&gt;know&lt;/em&gt; that it is bad for our mental
health, yet rarely do we talk about it on a systemic level.  Why do we
all put up with these circumstances and why do we all keep making
excuses for the systems that make us miserable?  This, to me, is the
core of how many people engage with modern social media platforms.&lt;/p&gt;
&lt;p&gt;I had taken longer breaks from Twitter before, deleting the app off my
phone, bargaining with myself about how much I wanted to share.  But I
always fell back into its orbit.  I feel it's appropriate to use the
language of addiction around this subject.  And it wasn't until I
truly admitted to myself that I had a problem that I was able to let
go and examine the frameworks through which I had engaged with online
society, and the impact that these systems had had on me and my life.&lt;/p&gt;
&lt;p&gt;In the following sections of this article I want to outline some of
the mechanisms that have kept me hooked for so long and have made it
&lt;em&gt;extremely difficult&lt;/em&gt; to escape its consequences.  Lastly I also want
to talk about a possible way out and some alternatives as to how to
engage with &lt;em&gt;the online&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;The fear of missing out&lt;/h2&gt;
&lt;p&gt;Social media weaponises "FOMO", the &lt;em&gt;fear of missing out&lt;/em&gt;.  Twitter is
particularly good at this, advertising itself as the platform "to know
what's happening".  &lt;em&gt;Twitter users know it first&lt;/em&gt; is the actual
current tag-line to entice you into signing up.&lt;/p&gt;
&lt;p&gt;I believe social media has had the strangle-hold over our collective
psyche at least in part because "we" have designed a society where
being outside your own home is miserable, exhausting, and toxic.  To
have a good time outside you need to spend money, or you need to
engage in some kind of social event.  Merely the act of &lt;em&gt;being
outside&lt;/em&gt; is punished through car-centric design and architecture.  Not
to mention the noise that personal motor vehicles cause and their
effect on the mental well being of city dwellers.  I have been
fortunate in a way, living in the suburbs of Berlin (for the time
being), meaning that I only have to walk for about 5 minutes before I
end up in the Brandenburg forest.&lt;/p&gt;
&lt;p&gt;This has actually been a life-saver.  It has meant that I was able to
escape stressful situations over the last few years (of which there
have been &lt;em&gt;too many&lt;/em&gt;) by going for a walk, disconnecting through
nature, and re-grounding myself in a very basic way.  It seems silly
to even talk about this but having the ability to &lt;em&gt;go for nice a walk&lt;/em&gt;
has been linked to a significant improvement of mental health&lt;sup id="fnref:nature"&gt;&lt;a class="footnote-ref" href="#fn:nature"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;The unfortunate reality is, that many people do not have access to
this basic human need, and so, social media can often seem like an
enticing alternative.  This is an especially important angle
considering the way addictive design is used in social media apps to
give you a false sense of gratification.&lt;/p&gt;
&lt;p&gt;Over the last decade we have all become more &lt;em&gt;and more&lt;/em&gt; aware of
global events to the detriment of our collective mental health.
Permanently wired into "what's happening" creates the illusion of
control, where none is possible.  &lt;em&gt;I'm not arguing for ignorance here
either&lt;/em&gt;.  I don't think that shutting yourself off to what is
happening in the world is a reasonable alternative.  But we &lt;em&gt;must
examine&lt;/em&gt; the ways that our current modus operandi is damaging to us.
We must especially become aware of how the &lt;em&gt;fear of missing out&lt;/em&gt; will
drive us to engage for longer and beyond our personal limits to handle
the stress that knowing the horrors of the global capitalist system
causes within us.&lt;/p&gt;
&lt;h2&gt;Becoming a brand&lt;/h2&gt;
&lt;p&gt;When I created my Twitter account back in 2012 it was for me to
shit-post about video games, and to keep in touch with various friends
around my life.  Around 2017 a slow shift started to appear in the way
that I used my account.  It was gradual, and imperceptible to me at
first.  Over time I was changing from &lt;em&gt;being a person&lt;/em&gt; to &lt;em&gt;being a
brand&lt;/em&gt;.  This will probably not be everyone's experience.  I know
people who are 100% the same in person as they are on Twitter (even
with large-ish follower counts) and I assume this is not a problem
that everyone is going to have.&lt;/p&gt;
&lt;p&gt;Still, it is something that I have struggled with, and that I &lt;em&gt;know&lt;/em&gt;
people much "larger" than me are also struggling with.  My audience
on Twitter was still relatively small, yet I stopped feeling confident
in being able to share myself as-is on the site.  In one part this was
because it made me uncomfortable to share intimate and private parts
of my life with thousands of people online that I didn't know.  In
other parts it was because my political and societal outlook shifted
and radicalised.  My views became less socially acceptable, and so, I
started filtering myself online.  This was small at first, but over
time it built up a wall between me and my Twitter brand.&lt;/p&gt;
&lt;p&gt;On one hand I felt this weird obligation to use my platform, &lt;em&gt;to
leverage&lt;/em&gt; the following that I had for the work that I was doing and
that was important to me.  On the other hand I felt repulsed by the
idea of having to pretend to be someone I wasn't to be accepted.&lt;/p&gt;
&lt;p&gt;I want to quickly explore the shape and form of online communities
(through my experience obviously -- I have done some research into
this but sociologically things are more complex than this) because I
think it will be helpful to explain how this shift from "person" to
"brand" happened.&lt;/p&gt;
&lt;p&gt;Broadly speaking, internet communities fall onto a spectrum between
&lt;em&gt;specialist&lt;/em&gt; and &lt;em&gt;generalistic&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Specialist communities are those built around a specific common
interest.  This could be part of your identity, it might be a hobby,
or it might be a shared profession.  It's important to know that this
is only a &lt;em&gt;part&lt;/em&gt; of you and while it's easy to find people who are
also into &lt;em&gt;this thing&lt;/em&gt;, often any other overlap is coincidental or not
guaranteed to result in connections that you will want to maintain.
In my experience these communities end up feeling shallow because the
social overlap is limited to a particular subject.  It is certainly
possible to build otherwise nuanced relationships with people in these
spaces, but it's not as easy.&lt;/p&gt;
&lt;p&gt;(Again, this model has its limitations, especially for communities by
marginalised folks, where a shared life experience provides a common
backdrop to society that influences every other aspect of someone's
life.)&lt;/p&gt;
&lt;p&gt;Generalist communities are those that are polymorphic, meaning that a
(more or less) diverse crowd of people come together (maybe under a
&lt;em&gt;very&lt;/em&gt; loosely defined banner) to talk to each other.  While it will be
possible to meet people who share a wide variety of interests to you,
it can also feel like searching for a needle in a hay stack because
there are a lot of people, and finding potential friends in a huge
diverse crowd of people who you may not have many things in common
with can be difficult.&lt;/p&gt;
&lt;p&gt;Most social media sites will reflect any number of community
variations on this spectrum and Twitter is no exception in that.
There are subtle differences in how these categories work depending on
how you engage with the platform.  In my time on Twitter as an
individual I felt like I was building multiple sets of specialist
communities.  Once I &lt;em&gt;became a brand&lt;/em&gt; however this shifted and the
focus relied more on building a generalist audience.  No longer could
I assume that my followers were sympathetic to me, and so came the
consequences of presenting my authentic self in front of an
ever-increasing crowd of judges.&lt;/p&gt;
&lt;h2&gt;The "algorithm" &amp;amp; the timeline&lt;/h2&gt;
&lt;p&gt;A few years ago social media platforms started pushing for
non-chronological, behaviour curated timelines.  At first this caused
an uproar, when users stopped seeing their friends' posts in their
feed and instead started seeing random sponsored content; whether
someone had paid for it or merely &lt;em&gt;engaged with it&lt;/em&gt;.  At this point
you will also see content recommendations from groups and hashtags.&lt;/p&gt;
&lt;p&gt;But this controversy died down over time, as could maybe have been
expected.  Ironically running a poll on Twitter these days whether
people use the algorithmic or chronological timelines yields in a
heavy filter bias, which "shows" that most people are using the
chronological timeline.  Of course, most of your followers won't
actually see your post in the end.&lt;/p&gt;
&lt;p&gt;Non-chronological timeline design is at the centre of modern corporate
social media sites.  The goal is no longer to facilitate meaningful
exchange between users and instead the focus has shifted to keeping
users "engaged" for longer.  The customers are ad-buyers and the
commodity is your time.  This is another open secret that we all
conveniently ignore.  &lt;em&gt;You may think that you are above this&lt;/em&gt;, that
you can't be manipulated into spending more and more of your precious
time on this planet in front of your phone or laptop, refreshing,
scrolling, refreshing, scrolling, but considering that the designers
of these tools fall prey to their own creations &lt;sup id="fnref:sd"&gt;&lt;a class="footnote-ref" href="#fn:sd"&gt;2&lt;/a&gt;&lt;/sup&gt;, you are not.&lt;/p&gt;
&lt;p&gt;Importantly "algorithms" are also arbiters of content, and in the
ideal case, equalisers.  Someone with very few followers can have a
post "blow up" if the algorithm blesses it, and someone with many
followers can have their work buried if the algorithm deems it
unsuitable.  This might not be a problem for your shit posts.  But
when you try to use a platform to advertise your work, especially when
you are financially dependent on it, this can be a scary prospect.&lt;/p&gt;
&lt;p&gt;Twitter is by far not the worst platform for this, nor is it the one
with the worst effect.  Sites like YouTube, where artists spend
hundreds of hours creating videos, are much more affected by this.
But the mechanisms are fundamentally the same.&lt;/p&gt;
&lt;h2&gt;Social capital vs. Perceived social capital&lt;/h2&gt;
&lt;p&gt;Algorithmic timelines on Twitter feed into the dilemma between our
&lt;em&gt;perceived&lt;/em&gt; social capital and our &lt;em&gt;actual&lt;/em&gt; social capital.  Social
media has largely become mandatory for branding, for advertising your
work in some way.  Especially if you are self employed or an artist of
any kind, your livelihood may depend on your ability to promote your
work and getting whatever you are doing in front of the eye balls of
other people.  Having a large following on Twitter will definitely
help with this, but it's by no means a guarantee.  Other platforms
suffer from this too (again: see problems that smaller YouTube
creators face&lt;sup id="fnref:salari"&gt;&lt;a class="footnote-ref" href="#fn:salari"&gt;3&lt;/a&gt;&lt;/sup&gt; that those who have "made it" no longer do).&lt;/p&gt;
&lt;p&gt;I think this is the aspect that I struggled with the longest.  I
didn't judge my Twitter account by the actual social capital that I
gained from it, I judged it by the &lt;em&gt;perceived social capital&lt;/em&gt; that I
thought to gain from sticking around.  The reality of the situation
was that any time I would genuinely talk about my work, advertise
something that I had made or was proud of, my Twitter audience was
useless.  Almost as an insult the most popular of my posts were shit
posts.  Having recently talked about this with some friends, both with
smaller and significantly larger audiences, this seems to be a
somewhat common experience.&lt;/p&gt;
&lt;p&gt;It's extremely difficult to distinguish these two values and to really
understand what actual benefit you are gaining from sticking to a
known habit.  A lot of it is going to be projection.  And fantasies
will make it hard to quit.  Don't think about the one time your work
was valued, think about the hundreds of times that your work felt
ignored.&lt;/p&gt;
&lt;h2&gt;Whatever current drama is happening&lt;/h2&gt;
&lt;p&gt;Twitter is stuck in a perpetual cycle of despair.  One could argue
that this is a more general trend in the 24-hour news-cycle-society
that we live in, but Twitter manages to put its unique spin on it.&lt;/p&gt;
&lt;p&gt;More importantly, no matter what is currently going on, you will find
a lot of people threatening to leave Twitter &lt;em&gt;if X&lt;/em&gt; happens or &lt;em&gt;if Y
doesn't&lt;/em&gt; happen.  But they never do.  At this point I don't think
anything is going to make them actually leave Twitter.  No design
changes to the platform did it, the Nazis didn't, Donald Trump didn't
do it, this acquisition by a certain apartheid profiteer won't do it
either, and whatever the next thing is that's going on in the future
won't do it either.&lt;/p&gt;
&lt;p&gt;I truly believe that Twitter brings out the worst in people, whether
it's the capitalist grifters who need an audience, or self righteous
trolls who perpetually feed the discourse.  It gives you the illusion
of control by letting you curate an experience bubble, while barely
even giving you that.&lt;/p&gt;
&lt;p&gt;In the end, Twitter has become too large an investment in the hearts
and minds of its users to give up.  And to be honest, I've had enough
of it to want to make excuses anymore.&lt;/p&gt;
&lt;h2&gt;In conclusion&lt;/h2&gt;
&lt;p&gt;I was in London at the beginning of October, watching the closing
performance of &lt;a href="https://diva-magazine.com/2022/06/16/the-prince-abigail-thorn/"&gt;The
Prince&lt;/a&gt;
at the Southwark Playhouse.  After the play I walked around Elephant &amp;amp;
Castle with a friend and we talked about social media and the
performances we all play for each other (in line with the play, which
you should definitely watch on or offline if you have the chance).&lt;/p&gt;
&lt;p&gt;It was in that moment that I went &lt;em&gt;fuck it&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;We only get so many years on this planet and the world is a truly
horrific and heart breaking place.  And we are going to need all of
our collective strength to change things.  If we even still can.  One
thing I am certain of however: &lt;em&gt;social media culture is not going to
help us&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Corporate social media has been designed to keep us engaged to the
detriment of our mental health.  Being informed of something does not
necessarily increase your agency over the situation.  Instead it may
simply be giving you the illusion of control by exploiting your
emotional reactions and well-being.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Delete your Twitter account.  You can do it.  I believe in you :)&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;/ Afterword&lt;/h2&gt;
&lt;p&gt;One &lt;em&gt;last&lt;/em&gt; thing I want to talk about is alternatives.  I am still
online, I still talk to friends.  I even, in a sense, still have a
public persona.  I use &lt;em&gt;the fediverse&lt;/em&gt;&lt;sup id="fnref:fedi-intro1"&gt;&lt;a class="footnote-ref" href="#fn:fedi-intro1"&gt;4&lt;/a&gt;&lt;/sup&gt; &lt;sup id="fnref:fedi-intro2"&gt;&lt;a class="footnote-ref" href="#fn:fedi-intro2"&gt;5&lt;/a&gt;&lt;/sup&gt; to
advertise my work, and have done so for years.  In fact, every time I
posted something on Twitter, I also posted in on fedi.  The
differences in feedback were astounding.  It wasn't that &lt;em&gt;every&lt;/em&gt; post
got a lot of attention, but the ones I truly cared about did.  Not
only were they widely shared, they created &lt;em&gt;conversation&lt;/em&gt;... honest to
god feedback, discussion, and interest.  Something practically unknown
to me on Twitter.&lt;/p&gt;
&lt;p&gt;Now... as a certain TV writer posted on mastodon.social back in 2017:
&lt;em&gt;"I wonder if being on here during my twitter breaks is like when I
tried to quit smoking using cigars"&lt;/em&gt;, and he might be right (love your
work Dan).&lt;/p&gt;
&lt;p&gt;I think the crux of the issue is how you approach your use of
technology, and what kind of interactions that technology fosters.  I
don't want to turn this article around in the afterword and insinuate
that any problematic relationship with social media is your own fault.
&lt;em&gt;It isn't&lt;/em&gt;.  But, I think you have more power over your habits that
you give yourself credit for.&lt;/p&gt;
&lt;p&gt;I have three accounts on the fediverse: a public one, where I post
realistically the same stuff I posted on brand-Twitter before it made
me miserable, a semi-public one, where I share selfies, random things
I'm working on, and a sort of micro-blog, and a private one where I
talk to just close friends.  The expectation to have multiple accounts
with varying degrees of publicness is ingrained into the fediverse in a
way that I've never really seen it on Twitter.&lt;/p&gt;
&lt;p&gt;And yet, I wonder how much time I spend on the elephant website and
whether it is useful to my life.  In the end everything is a balancing
act.  And while I can still see a lot of good reasons to stick around
on the fediverse (imperfect as it may be&lt;sup id="fnref:MST"&gt;&lt;a class="footnote-ref" href="#fn:MST"&gt;6&lt;/a&gt;&lt;/sup&gt;), I can no longer say
the same for Twitter.&lt;/p&gt;
&lt;p&gt;Giving up on Twitter doesn't mean giving up on online society.
Especially if you live in an isolating place (like the suburbs, or
more generally North America), it can be incredibly helpful to find a
wider community online.&lt;/p&gt;
&lt;p&gt;But please don't use a switch in platform as an excuse to not &lt;em&gt;examine
the underlying relationships&lt;/em&gt; you have with the online.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:nature"&gt;
&lt;p&gt;&lt;a href="https://www.nature.com/articles/s41598-022-15004-0"&gt;https://www.nature.com/articles/s41598-022-15004-0&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:nature" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:sd"&gt;
&lt;p&gt;Watch "The Social Dilemma (2020)".  It's not a &lt;em&gt;great&lt;/em&gt;
documentary; in my opinion it falls short in its analysis of what
social media and the manipulation of public opinion actually
means, outside of a very narrow "someone help me balance this, my
democracy is dying".  But there are some insightful interviews in
it, by people who have worked on various social media sites,
talking about their own experiences with social media addiction.&amp;#160;&lt;a class="footnote-backref" href="#fnref:sd" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:salari"&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=0HiNVQkamA4"&gt;https://www.youtube.com/watch?v=0HiNVQkamA4&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:salari" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:fedi-intro1"&gt;
&lt;p&gt;&lt;a href="https://fediverse.info"&gt;https://fediverse.info&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:fedi-intro1" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:fedi-intro2"&gt;
&lt;p&gt;&lt;a href="https://wordsmith.social/elilla/a-futuristic-mastodon-introduction-for-2021"&gt;https://wordsmith.social/elilla/a-futuristic-mastodon-introduction-for-2021&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:fedi-intro2" title="Jump back to footnote 5 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:MST"&gt;
&lt;p&gt;&lt;a href="https://sporks.space/2021/02/02/mastodon-really-is-crumbling-and-it-will-only-get-worse/"&gt;https://sporks.space/2021/02/02/mastodon-really-is-crumbling-and-it-will-only-get-worse/&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:MST" title="Jump back to footnote 6 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Tue, 18 Oct 2022 00:00:00 +0200</pubDate><guid>tag:None,2022-10-18:/blog/why-i-deleted-my-twitter-and-why-maybe-you-should-too</guid><category>Blog</category><category>culture</category><category>tech</category></item><item><title>Embrace being proven wrong</title><link>/blog/embrace-being-proven-wrong</link><description>&lt;p&gt;I recently posted an article on my Twitter feed about the shortcomings
of Flatpak.  It resonated with me and my opinions on a subject that,
it turned out, I didn't know enough about.  I had conversations with
people who were far bigger experts in this area than me, both some in
favour of Flatpak, and some sceptical, and came to new conclusions.&lt;/p&gt;
&lt;p&gt;Don't get me wrong: I'm still not 100% convinced.  I still have
criticism of Flatpak, as I think anyone can have about anything.&lt;/p&gt;
&lt;p&gt;But I opted to delete my tweet because I didn't feel comfortable with
the hyperbole of the article.  Worse even: in some corners of the
internet the article had garnered a reputation for "speaking truth to
power", feeding into a weird Red Hat conspiracy theory that I felt
even more uncomfortable with.&lt;/p&gt;
&lt;h2&gt;Discourse neurology&lt;/h2&gt;
&lt;p&gt;This style of rhetoric, the "taking apart an argument so I don't have
to think about it too hard", has become very common in modern
discourse.  This is driven by the "fight or flight" response of the
amygdala in our brains&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;.  A feeling of physical anxiety floods us
when we are on the defensive, for whatever reason.  And all logic goes
out the window.&lt;/p&gt;
&lt;p&gt;Many of the arguments you see online (and many offline too, don't get
me wrong!) center around this emotional response and it is one that
our culture fosters as well.&lt;/p&gt;
&lt;p&gt;Admitting to being wrong is seen as a weakness and connected to shame,
a loss of status, and humiliation.  And so, we are never wrong.  We
attack our intellectual oponents in order to relieve ourselves of the
responsibility of having to engage with an argument that makes us
uncomfortable.  This is how filter bubbles get created too&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2&gt;Hope for the future&lt;/h2&gt;
&lt;p&gt;But that's not how it needs to be.  And that's what this blog post is
about.&lt;/p&gt;
&lt;p&gt;Because let's face it: we're all wrong about most things.  There are
too many things to be known, and too little time to know them all.
And because society favours whitty comebacks at surface level
discourse, this doesn't change the fact that we are filtering
ourselves from properly engaging with arguments that we might find
uncomfortable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is an antidote however: radical vulnerability and humility.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Being wrong is an opportunity to learn something new and to broaden
your perspective on some topic you didn't understand previously.
Approach arguments that make you uncomfortable with an open curiocity
and you will find yourself agreeing with more things than you
previously thought.&lt;/p&gt;
&lt;p&gt;And this isn't about just changing your opinions either.  By engaging
more openly with things you disagree with you can actually increase
your resolution on ideas that you hold dear.  I'd also like to point
out that not all ideas are equally valid.  Fuck you if you think this
justifies debating nazis...&lt;/p&gt;
&lt;p&gt;Ultimately I want to approach life with a curiocity that doesn't
exclude me from new and exciting things that may be happening in the
communities I'm in, or from ignoring uncomfortable truths about how
the system we are forced to live in works.&lt;/p&gt;
&lt;p&gt;And maybe, if enough of us do this, we can make this world just a
little bit better too.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Fight-or-flight_response#Reaction"&gt;https://en.wikipedia.org/wiki/Fight-or-flight_response#Reaction&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Filter_bubble#Ethical_implications"&gt;https://en.wikipedia.org/wiki/Filter_bubble#Ethical_implications&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Wed, 13 Apr 2022 00:00:00 +0200</pubDate><guid>tag:None,2022-04-13:/blog/embrace-being-proven-wrong</guid><category>Blog</category><category>culture</category><category>politics</category></item><item><title>My attempt at synthtober</title><link>/blog/my-attempt-at-synthtober</link><description>&lt;p&gt;It's October!  This year was weird, maybe even more so than 2020.  The
year felt very short, and very long at the same time to me; more so
than I usually feel around this time of year.&lt;/p&gt;
&lt;p&gt;As the dark season comes around it's good to remind yourself to focus
on the things you really care about.  Make sure you get plenty of
light, maybe change those 2700K bulbs for something 4000K+.  Colour
temperature can make a real difference whet it comes to SAD...&lt;/p&gt;
&lt;p&gt;Anyway, it's October, the month where everybody draws or hacks or
drinks themselves to happiness.  A friend mentioned last weekend that
she was going to try to do &lt;em&gt;synth&lt;/em&gt;-tober: creating a small song or jam or
whatever every day.  I haven't published a song on my bandcamp in
almost (or over?) a year so it's high time I get out of my rut.&lt;/p&gt;
&lt;p&gt;This blog post will be updated repeatedly throughout the month.  I
doubt that I will manage to make a song every day, but I want to
manage at least two a week.&lt;/p&gt;
&lt;p&gt;Some uploads will be very unpolished songs, others might just be me
fucking around with interesting sound design.  We'll see :)&lt;/p&gt;
&lt;p&gt;Happy October!&lt;/p&gt;
&lt;h2&gt;Entry 1: Uneasy&lt;/h2&gt;
&lt;p&gt;&lt;img src="/images/synthtober1.jpg" 
     alt="A picture of the Arturia Drumbrute Impact and Novation Circuit on my desk" /&gt;&lt;/p&gt;
&lt;p&gt;Technically this started as a jam but then I saved the patterns and
went to work so that technically makes it a song, right?  I have been
playing around with my
&lt;a href="https://diode.zone/w/pFUiRDya9i45ESQPC2zkWi"&gt;Octatrack&lt;/a&gt; a lot
recently so I wanted to get back to basics.  I grabbed my analogue
drum machine and the Circuit and used it for drums and synths.  The
result is...eh, listen for yourself!&lt;/p&gt;
&lt;iframe width="100%" height="150" scrolling="no" frameborder="no" src="https://music.kookiejar.tech/front/embed.html?&amp;amp;type=track&amp;amp;id=3233"&gt;&lt;/iframe&gt;

&lt;h2&gt;Entry 2: forest&lt;/h2&gt;
&lt;p&gt;&lt;img src="/images/synthtober2.png" 
     alt="A screenshot of my DAW with an audio recording at the top, several layers of effects automations, and an effects chain at the bottom" /&gt;&lt;/p&gt;
&lt;p&gt;I haven't picked up my guitar in &lt;em&gt;months&lt;/em&gt;.  In fact, a thick layer of
dust had collected on it.  Now... my guitar is old and kinda broken.
It only has 5 strings (like all the pros recommend), and it's internal
wiring seems a bit shoddy with the top pick-up periodically no longer
picking-up.&lt;/p&gt;
&lt;p&gt;What I put together here is an effects chain in bitwig, which I
fiddled with a bit while and after playing some random chords and
riffs.  The layers of effects almost hide the fact that I am extremely
out of practice at playing the guitar ;) Hope you enjoy!&lt;/p&gt;
&lt;iframe width="100%" height="150" scrolling="no" frameborder="no" src="https://music.kookiejar.tech/front/embed.html?&amp;amp;type=track&amp;amp;id=3238"&gt;&lt;/iframe&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Tue, 05 Oct 2021 00:00:00 +0200</pubDate><guid>tag:None,2021-10-05:/blog/my-attempt-at-synthtober</guid><category>Blog</category><category>music</category><category>october</category></item><item><title>Devebruary (Week 2)</title><link>/blog/devebruary-week-2</link><description>&lt;p&gt;At the beginning of the month a friend a I decided to spend four weeks
seriously hacking on our games, and blogging about it.  We called this
event "Devebruary": this is entry for week 2.  You can find &lt;a href="/blog/devebruary-week-1/"&gt;week 1
here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Current state of the project&lt;/h2&gt;
&lt;p&gt;This post will undoubtebly be much shorter than last week's.  I didn't
get to work on the game as much as I would have liked to.  I did
however spend a bunch of time working on basics that I need to
continue.&lt;/p&gt;
&lt;p&gt;I wrote a map file loader for the server (and client too I guess),
which wasn't too hard.  The next problem I had was that I didn't just
want to write one of these files by hand (which is certainly
possible), but already felt like I needed to have a way to edit maps
in-game.  So I started working on a map editor.  You can launch this
state by passing &lt;code&gt;--editor&lt;/code&gt; to the client as an argument.&lt;/p&gt;
&lt;p&gt;As part of this I also needed to deal with the fact that the &lt;code&gt;ggez&lt;/code&gt;
crate doesn't expose any sort of UI element system.  It bundles the
&lt;code&gt;lyon&lt;/code&gt; crate with some utilities to draw meshes, which I decided to
use to write UI elements.&lt;/p&gt;
&lt;p&gt;I started with a simple button which can be clicked.&lt;/p&gt;
&lt;p&gt;&lt;img alt="RST Node button example" src="/images/rst-node-week2.png"&gt;&lt;/p&gt;
&lt;p&gt;Next up I tackled the input and event system in &lt;code&gt;ggez&lt;/code&gt;.  There is a
central trait called &lt;code&gt;EventHandler&lt;/code&gt;, which provides a set of functions
that should be called during update, render, and other event times.
The problem is that there's no mechanism to provide the main event
loop with more than one of these objects, meaning that a lot of
user-space code ends up just passing these objects around and calling
the correct function on something.&lt;/p&gt;
&lt;p&gt;So instead of doing that I wrote an &lt;code&gt;EventLayer&lt;/code&gt; abstraction which
takes a set of event handlers (which can also be created during
runtime!) and proxies events to them.  This obviously adds some
run-time overhead, but the effect on code quality has so far been very
positive.&lt;/p&gt;
&lt;h2&gt;So this week then...&lt;/h2&gt;
&lt;p&gt;I hope to finish my input refactoring today, and hook up the UI
initialisation code to it.  Then I can start building UI building
blocks that automatically react to events as they happen.&lt;/p&gt;
&lt;p&gt;The same input trait that buttons implement should also be implemented
by all other game elements: nodes need to be selectable after all...&lt;/p&gt;
&lt;p&gt;I'm wondering if there should be a management type in between the
input events and the game entities, or if its sufficient to have them
each be managed on their own.&lt;/p&gt;
&lt;p&gt;Also hopefully I'll have more screenshots next week&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Mon, 22 Feb 2021 00:00:00 +0100</pubDate><guid>tag:None,2021-02-22:/blog/devebruary-week-2</guid><category>Blog</category><category>/dev/diary</category><category>hackerthon</category></item><item><title>Devebruary (Week 1)</title><link>/blog/devebruary-week-1</link><description>&lt;p&gt;Last week a friend and I decided to spend four weeks more seriously
hacking on our games and blogging about it.  We called this event
"Devebruary", even though February had already started.  This is my
first post.&lt;/p&gt;
&lt;h2&gt;The current state&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Relay concept part" src="/images/rst-concepts1.png"&gt;&lt;/p&gt;
&lt;p&gt;I've been working on a game called &lt;em&gt;"RST Node"&lt;/em&gt; (read "Reset Node")
for the last few years, albeit only conceptually.  It is a 2D (top
down) RTS, set on a computer network.  A match consists of multiple
players starting with a single node on this network, attempting to
capture as many of the surrounding computers as they can.  As part of
this they need to build compute clusters to gain resources, and attack
the enemy with various exploits.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Compute node concept art" src="/images/rst-concepts2.png"&gt;&lt;/p&gt;
&lt;p&gt;I started programming on this game last year in January, but only
worked on it for about a month before running out of time and energy
(did something else happen in 2020? Can't remember).  The game is
written in Rust and AGPL-3.0, seeing as it uses a component from my
research project (&lt;a href="https://lib.rs/crates/ratman"&gt;Ratman&lt;/a&gt;), which is also licensed under the AGPL-3.0.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Attack node concept part" src="/images/rst-concepts3.png"&gt;&lt;/p&gt;
&lt;h2&gt;What I've done this week&lt;/h2&gt;
&lt;p&gt;The code up to this week was entirely backend focussed.  I had layed
out the basic structure of units, abilities, and matches.  Nothing was
being drawn yet.  To render a client I'm using the [&lt;code&gt;ggez&lt;/code&gt;] Rust
crate, which is a Rust clone of the [&lt;code&gt;love&lt;/code&gt;] framework.  I'm not a
&lt;em&gt;huge&lt;/em&gt; fan, and if the game was any more graphically ambitious I'd
want to find something else.  But seeing as I'm only really drawing
simple 2D graphics and doing some camera (i.e. viewport) manipulation,
this will do.&lt;/p&gt;
&lt;p&gt;The following screenshot demonstrates the current client state.  Sexy,
I know!&lt;/p&gt;
&lt;p&gt;&lt;img alt="Current game state screenshot" src="/images/rst-node-week1.png"&gt;&lt;/p&gt;
&lt;p&gt;The asset loading probably took the most effort in this demo.  I'm
creating art assets in inkscape as SVGs, loading them at game start,
and converting them into sprite textures with &lt;code&gt;librsvg&lt;/code&gt;.  This way the
game can scale across many resolutions while not requiring a very
large assets directory.&lt;/p&gt;
&lt;p&gt;On the server side I looked into using QUIC for client-server
communication, but the only crates I could find were either
synchronous, or used tokio.  The rest of the game is built on
async-std, and I didn't feel like either adding a second runtime &lt;em&gt;or&lt;/em&gt;
porting the game.  So instead for now I'm using the async-std
&lt;code&gt;UdpSocket&lt;/code&gt; abstraction, and if I run into packet delivery problems
later, I'll either switch to &lt;code&gt;TcpSocket&lt;/code&gt;, or write an async-std
wrapper with the [&lt;code&gt;quinn-proto&lt;/code&gt;] crate.&lt;/p&gt;
&lt;h2&gt;What I'm planning for next week&lt;/h2&gt;
&lt;p&gt;&lt;img alt="General node design" src="/images/rst-concepts0.png"&gt;&lt;/p&gt;
&lt;p&gt;So far the rendering is largely disconnected from the backend map
types.  Ultimately the renderer needs to be able to render a mesh of
nodes that are distributed through a 2D space, with links between
them.  Each link also needs to have a length based on the distance
between two nodes, that determines how long it takes packets to
traverse it.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Packet and trail designs" src="/images/rst-concepts0-1.png"&gt;&lt;/p&gt;
&lt;p&gt;I already defined a structure of how maps work (as sets of nodes and
links), although currently without x/y coordinates.  In the next week
I want to integrate map loading into the asset loader (and also make
the asset loader available to the server which ultimately needs to
load the map configurations)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Maybe&lt;/em&gt; I'll also make enough progress to have a first packet traverse
a link.  But we'll see!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Sun, 14 Feb 2021 00:00:00 +0100</pubDate><guid>tag:None,2021-02-14:/blog/devebruary-week-1</guid><category>Blog</category><category>/dev/diary</category><category>hackerthon</category></item><item><title>Irdest: history of a fork</title><link>/blog/irdest-history-of-a-fork</link><description>&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; we're forking qaul.net to &lt;a href="https://irde.st"&gt;&lt;strong&gt;Irdest&lt;/strong&gt;&lt;/a&gt;!
This includes myself, and four other developers who have been
on-and-off working on qaul in their free time over the last year.  We
have a new domain, have largely re-branded the existing code-base and
website, and are submitting &lt;a href="https://projects.freifunk.net/#/projects"&gt;Google Summer of Code
projects&lt;/a&gt; to find people who
would like to contribute code while getting paid.&lt;/p&gt;
&lt;h2&gt;The background&lt;/h2&gt;
&lt;p&gt;If you're a regular follower of my work, you may know that I've been
the lead developer of a project called &lt;code&gt;qaul.net&lt;/code&gt;, a decentralised
mesh routing application and app development toolkit.  The project
itself is not mine and was started around 2011; I joined it in 2016 as
part of my Google Summer of Code.  But I quickly took over a lot of
the core planning and development aspects, and even worked on it as my
full-time research job from 2019 to 2020.&lt;/p&gt;
&lt;p&gt;In the summer of 2020, the Open Tech Fund, which was funding
development on the project, was defunded, and development stopped for
a few months.  During this time, I was also recovering from some
health issues, and needed to take a break from the project.&lt;/p&gt;
&lt;h2&gt;Where things went wrong&lt;/h2&gt;
&lt;p&gt;Software projects are social entities of the people who work on them,
not merely technical problems to be solved.  And while I have enjoyed
my time working on qaul.net, I also feel like I can no longer overlook
the problems in how the project is organised.  I don't want to talk
about the specifics, and I won't mention anyone by name.  A lot of my
issues with the project revolve around how one of the original
maintainers sees the project itself, and his role compared to others
who work with him.&lt;/p&gt;
&lt;p&gt;Ultimately, social relationships, whether personal or professional,
need to be rooted in mutual respect and understanding.  Neither of
those two are the case with regards to the original maintainer in
question.&lt;/p&gt;
&lt;p&gt;Over the last year and a half, I have repeatedly brought up issues
with him, about his conduct, the way that he approached my work, and
our interactions, and have tried to engage with him in conversation
about our working relationship, and how we might improve it.  In all
of this time, I don't think that I have had a single productive
conversation with him, as equals.&lt;/p&gt;
&lt;p&gt;It became apparent to me, that working with this person would continue
to negatively affect my mental health, and so I (with the help of some
amazing friends!) made preparations to fork the project.&lt;/p&gt;
&lt;h2&gt;Why now?&lt;/h2&gt;
&lt;p&gt;Initially we were planning to keep this as a very soft fork.  The
"upstream" project wasn't really doing anything.  Nobody except me was
putting in code at that time, and it was a happy neutral ground where
we were prepared to take the project in a different direction, but
didn't need to force the issue.&lt;/p&gt;
&lt;p&gt;Yesterday, the original maintainer announced that qaul.net had
received new funding.  He e-mailed me to inform me that he had undone
a bunch of work I had put in to improve our website and also removed
my access from most of our infrastructure.&lt;/p&gt;
&lt;p&gt;It became apparent that a low-key fork was no longer possible.  So
instead, we went ahead with some of the final re-branding we had been
putting off, and are going ahead with the fork.&lt;/p&gt;
&lt;h2&gt;Why write this?&lt;/h2&gt;
&lt;p&gt;I want to work on this project, whether I get paid for it or not.  I'm
in the fortunate position of being able to put in time on the project
while doing other jobs, or in between clients.&lt;/p&gt;
&lt;p&gt;My main concern is not having to interact with the original
maintainer in question on a regular basis, and not working in a
structure which is authoritatively structured around him.&lt;/p&gt;
&lt;p&gt;I write this blog post as a warning to anyone who is interested in
contributing to qaul.net, and might have to interact with this person
as well.&lt;/p&gt;
&lt;p&gt;It would make me very happy to see more people engage with qaul and
getting paid for their work.  I simply fear that people might be
walking into an abusive situation without being aware of the history.
And thus...this post.&lt;/p&gt;
&lt;p&gt;Ultimately, I'm mostly relieved.  The last attempt to communicate I
made was back in November, and since then I had heard next to nothing
until this announcement.  It is clear to me that my opinions and
feelings in this matter are not of importance, and so, I feel
justified to move on.&lt;/p&gt;
&lt;p&gt;Thank you for reading.  If you want to learn more about Irdest:
&lt;a href="https://irde.st"&gt;https://irde.st&lt;/a&gt;, and if you want to support my work
directly, I have a &lt;a href="https://github.com/sponsors/spacekookie"&gt;GitHub
sponsors&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Edits&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2021-04-04&lt;/strong&gt; - we changed the project name from qaul to Irdest.  A
  previous version of this page can be found in the web archive.&lt;/li&gt;
&lt;/ul&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Thu, 04 Feb 2021 00:00:00 +0100</pubDate><guid>tag:None,2021-02-04:/blog/irdest-history-of-a-fork</guid><category>Blog</category><category>/dev/diary</category><category>qaul</category></item><item><title>That's the wrong abstraction layer</title><link>/blog/thats-the-wrong-abstraction-layer</link><description>&lt;p&gt;I'm writing this post mostly to my future self, not any specific
project or piece of code I've seen other people write.  That's not to
say that I don't think this is something that probably applies to many
projects.  Sometimes it's easy to lose sight of what we're doing, and
it's good to be reminded.&lt;/p&gt;
&lt;p&gt;So to start at the beginning: I've been working on &lt;a href="https://git.spacekookie.de/kookienomicon/tree/apps/servers/octopus/supergit?h=main"&gt;supergit&lt;/a&gt;, a Rust
library to parse git repositories.  It's built on top of &lt;code&gt;libgit2&lt;/code&gt;
(and the &lt;code&gt;git2&lt;/code&gt; rust bindings), and aims to create a more Rustic
interface and type fascade for git repositories.  It also aims to
solve issues such as: rename detection, path-history, and subtree
management.  I'm writing this library for &lt;a href="https://git.spacekookie.de/kookienomicon/tree/apps/servers/octopus/?h=main"&gt;octopus&lt;/a&gt;, which will
eventually host my monorepo.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;supergit&lt;/code&gt; the main workflow is around iterating things, seeing as
git is an acyclical graph, and iterators are a decent way to view this
datastructure.  But git graphs can get pretty big.  I wanted the
iterator to be configurable in a way that allows someone to write a
tool that searches a whole repository history, while also making it
possible to step through a history 20 commits at a time (to implement
history pagination on a website, for example).&lt;/p&gt;
&lt;p&gt;Looking at the current API, this is how you would implement the
latter, for a &lt;code&gt;main&lt;/code&gt; branch:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;supergit&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Repository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// get your repository path somehow&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Repository&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_branch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;for_each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="fm"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{}: {}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;id_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That's easy enough, right?  But wait, why am I calling &lt;code&gt;.commit()&lt;/code&gt; on
&lt;code&gt;c&lt;/code&gt;.  Isn't it already a commit?  Well...sort of.  In &lt;code&gt;supergit&lt;/code&gt;, this
type is a &lt;code&gt;BranchCommit&lt;/code&gt;, because this is where things get
complicated.&lt;/p&gt;
&lt;h2&gt;Sort of like a tree, but not really&lt;/h2&gt;
&lt;p&gt;In git, rarely is a branch just a history of single commits.  Maybe
this is how some people think about their history, but it certainly
has never been the case for any of the repositories that I work on.
Basically the second you have more than one contributor, it's very
common for a history to have merge-commits in it.&lt;/p&gt;
&lt;p&gt;So how do we deal with that in an iterator?  The design I chose was to
wrap a &lt;code&gt;Commit&lt;/code&gt; object in another type, which can convey this state.
&lt;code&gt;BranchCommit&lt;/code&gt; is an enum and has three variants: &lt;code&gt;Commit&lt;/code&gt; (maybe I
should rename that to &lt;code&gt;Simple&lt;/code&gt; or something?), &lt;code&gt;Merge&lt;/code&gt;, and &lt;code&gt;Octopus&lt;/code&gt;
(if you don't know what an octopus merge is, don't worry about it.
Most people don't and they're very rare and weird).&lt;/p&gt;
&lt;p&gt;What &lt;code&gt;Merge&lt;/code&gt; and &lt;code&gt;Octopus&lt;/code&gt; contain are new &lt;code&gt;Branch&lt;/code&gt; handles (the type
returned by &lt;code&gt;get_branch()&lt;/code&gt;), meaning that for every split it's now up
to the user to decide whether they want to continue first-parent
(i.e. only ever follow the main branch line, ignoring the history of
merged branches), or if they want to enumerate the histories as well.
Most importantly: for every branch merge, you get to re-decide what
your iterator strategy should be: infinate, limited by number, or
limited up to a certain commit-hash.&lt;/p&gt;
&lt;p&gt;So far so good I thought, this is an okay enough interface for me to
work with.  But this is where some problems appeared.&lt;/p&gt;
&lt;h2&gt;File histories (and git internals)&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;(a slight de-tour through git - feel free to skip)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The main reason why I'm writing this more Rustic wrapper around
&lt;code&gt;libgit2&lt;/code&gt; is to make it easier to determine what the history of a file
has been.  This is pretty simple to find out via the git CLI (&lt;code&gt;git log
-- &amp;lt;your file here&amp;gt;&lt;/code&gt;), but not something that &lt;code&gt;libgit2&lt;/code&gt; exposes,
because that's not how git stores data.&lt;/p&gt;
&lt;p&gt;To git, all data is stored in a key-value store indexed by a SHA1
(soon to be SHA256 I think?) hash reference.  That applies to files,
full file trees, and commits as well.  Say we have a file &lt;code&gt;acab.txt&lt;/code&gt;,
we commit it and it gets the ID
&lt;code&gt;da39a3ee5e6b4b0d3255bfef95601890afd80709&lt;/code&gt; (the file ID, not the
commit ID!), but then we open it and write &lt;code&gt;ACAB&lt;/code&gt; in it, and commit
that again.  Now the file ID is
&lt;code&gt;99f069b8a0cbe4c9485a14fe50775d0f71deb4e7&lt;/code&gt;.  Both these files are
saved in the git object store, because after all you might want to go
back to the older version.&lt;/p&gt;
&lt;p&gt;But here's the thing: from the actual commits we can get two things:
the file tree at the time of commit, and the commit parents.  To
figure out what actually &lt;em&gt;changed&lt;/em&gt; in the commit, you have to diff it
against it's parents, which is exactly what &lt;code&gt;git show&lt;/code&gt; does if you
give it a reference to a commit.&lt;/p&gt;
&lt;p&gt;What this means is that if you want to have a library that grabs the
history of a path, well you'll have to go through all commits, and
check the tree for changes at that specific path.  Furthermore, that
won't actually let you know if a file has simply been renamed, only
that it has changed.  Further logic is required to figure out if the
file is the same, but just has a different name.&lt;/p&gt;
&lt;p&gt;And all of this is something that &lt;code&gt;supergit&lt;/code&gt; implements, behind a nice
Rustic API (I hope...).&lt;/p&gt;
&lt;h2&gt;Bloated abstractions&lt;/h2&gt;
&lt;p&gt;So I wrote a function that would, for a branch iterator, step along it
and check the history of a path, by diffing each commit with it's
parents, and tracking a path via the delta information in the diff.
But this is where I ran into problems.  Because my iterator design
always chose the first-parent to step through.  Other branches were
ignored, and because the function accepted an iterator and stepped it
internally, there was no way for my &lt;code&gt;file_history()&lt;/code&gt; function to
figure out the exact behaviour the user wanted.&lt;/p&gt;
&lt;p&gt;My first instinct was to implement branching in the &lt;code&gt;BranchIter&lt;/code&gt;
itself; allowing it to branch off, essentially pushing commits it
would have to get back to onto a stack, and resuming from a previous
position.  That turned out to be a really &lt;a href="https://git.spacekookie.de/kookienomicon/commit/apps/servers/octopus/supergit?h=main&amp;amp;id=0728c2f325e2eaac2c3b834260a8d0a97afaff63"&gt;bad idea&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It took me about an hour of banging my head against this abstraction
before I realised that it wasn't meant to be.  Sometimes systems are
self-contained, and adding more functionality takes a considerable
amount of effort, and begs the question, if it's really the right
choice to make.  Why add more functionality to an abstraction that
works fine on it's own?&lt;/p&gt;
&lt;p&gt;Instead, embrace composition, and add another layer on top, that can
use the previous.  You end up with a much more managable design, and
data can flow from one layer to the next.  Make sure that your
interfaces are flexible enough to be re-used, but don't think that
just because a component &lt;em&gt;could&lt;/em&gt; technically be responsible for some
work, that it really has to implement this work.&lt;/p&gt;
&lt;p&gt;And that's it basically.  Thanks for reading my ramblings about git
and one of my side-projects.  I hope I managed to make you think about
the way you build systems a bit, and maybe next time you are in a
situation similar to this one, don't be like me :)&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Wed, 11 Nov 2020 00:00:00 +0100</pubDate><guid>tag:None,2020-11-11:/blog/thats-the-wrong-abstraction-layer</guid><category>Blog</category><category>/dev/diary</category></item><item><title>"The good place" vs. the ethics of society</title><link>/blog/the-good-place-vs-the-ethics-of-society</link><description>&lt;p&gt;A few months ago I was bored and I decided to watch "The good place".
It's a show that had been introduced to me before, and I even watched
about half of the first season, before I kinda forgot about it.  It
had left me feeling mostly irritated, and uninterested, and so I moved
on with my life.  Up to the point where I felt &lt;em&gt;really&lt;/em&gt; bored, and I
started watching it again.&lt;/p&gt;
&lt;p&gt;I don't really wanna talk about the show from an art criticism
perspective.  It's quite fun to watch at times, the premise is quirky
and all the characters have something to set them apart that makes
them recognisable for someone who's bad at differentiating people.
But it's a comedy at it's core, and most of the "humour" left me
feeling kinda cold.  It didn't so much have jokes as much as just
vague references at jokes.&lt;/p&gt;
&lt;p&gt;Really, the show wasn't special, funny, or even bad enough for me to
really care about it too much.  There was however something in the
moral text, and subtext of the show that bothered me, that I've kept
thinking about.  And that's what this post is going to be about.&lt;/p&gt;
&lt;h2&gt;Good vs Evil&lt;/h2&gt;
&lt;p&gt;The main premise of the show is centred around the idea of "good
people" vs "bad people" (the good place vs the bad place).  It mirrors
heaven and hell, without putting a precise theological term on it,
because this concept has existed in various faiths throughout the
ages.&lt;/p&gt;
&lt;p&gt;The story follows a woman who gets sent to the good place even though
she's a horrible person.  Most of the first season is dedicated to
this mystery.  At first she thinks this is a mistake, until it becomes
apparent, that bad people being put into a fake "good place" is part
of a weird psychological punishment system in the bad place.  They are
in fact in the bad place.  When they find out about this, their
memories get wiped, and it starts from the beginning, with slight
alterations.  But the group figures out that they aren't in their
personal paradise again and again, and so their memories get wiped
again, and again.&lt;/p&gt;
&lt;p&gt;The show wants to demonstrate that people can get better, seeing as a
group of "bad people" were sent to a fake "good place", and improved
as people.  The permanence of "good people" and "bad people" is called
into question.  Some stuff happens, and the group of four people, and
one daemon who started taking a liking to them end up on the run.&lt;/p&gt;
&lt;p&gt;Throughout the plot it becomes apparent that the system is broken in
more subtle ways too: nobody gets to go to the good place anymore.
Nobody is good enough; too high are the standards of what counts as a
"good person".  Furthermore, when they manage to get into the good
place, it becomes clear that eternal bliss with no ups and downs, and
no end in sight is just a different type of hell.&lt;/p&gt;
&lt;p&gt;The show concludes by restructuring the system, making the "bad place"
not into a torturous nightmare, but a place where your actions and
emotions are being tested, and called into question.  The idea being
that there is no such thing as a "bad person", and that everybody
could go to the "good place", if they accepted that they have flaws,
and worked on them.&lt;/p&gt;
&lt;p&gt;They also mildly restructure the "good place" to have "an end", which
is death.  Isn't that nice, everybody gets to live their perfect life
in heaven, then they die.&lt;/p&gt;
&lt;h2&gt;Good people &amp;amp; bad people?&lt;/h2&gt;
&lt;p&gt;So that was the plot.  As I said, I'm not gonna criticise the show for
it's scene-to-scene writing, or even the overarching plot.  It mostly
tries (and manages) to be wholesome.  Although it has issues
throughout, that are rooted in a very flawed understanding of
philosophy and morality.&lt;/p&gt;
&lt;p&gt;The moral compass of the show is a character called Chidi, a professor
of moral philosophy who died and was sent to the "bad place".  He was
deemed a bad person because of his indecisiveness.  It is shown that
he tried to be a good person, but got too caught up in the details of
what that meant, which caused great pain to the people around him (and
which got him killed).&lt;/p&gt;
&lt;p&gt;Throughout the show he quotes Kant a lot, with some other racist white
men from history sprinkled in there.  His understanding of philosophy
isn't very deep, or nuanced.  Either he was supposed to be bad at his
job, at which point the show didn't really take the time to develop
this enough to be poignant, or it just demonstrates that the show was
written by people with basically no knowledge in this field.&lt;/p&gt;
&lt;p&gt;I argue that the way that "the good place" portrays philosophy and
moral choices in philosophical frameworks is very representative of
how our society works, and how people think about "good vs bad".&lt;/p&gt;
&lt;p&gt;But let's back up a bit.  For most of the show (if you watched it/
will) the thoughts it is trying the hardest to communicate are
"there's no bad people", "hell is a bad concept", etc.  This becomes
pretty obvious.  However, the larger system of afterlife remains
pretty much entirely un-examined.  Why is there an afterlife, and why
do we need one, these are questions the show never asks, or attempts
to answer.  Any critism against the system is phrased in a coy way,
that will lead to reform of it, not abolishment, i.e. changing what
the "good place" and "bad place" means, not their existence.&lt;/p&gt;
&lt;h2&gt;Moral individualism&lt;/h2&gt;
&lt;p&gt;I said the show is representative of how people think about morality,
and this doesn't just start and end at "what is a good person".  It
also applies to how the show deals with individualism.&lt;/p&gt;
&lt;p&gt;What is individualism you may ask?  I'm glad you did (not really, now
this post has to be longer...).  Individualism is one of the axiomatic
philosophies that the western world is built on.  It's the idea that
each individual is responsible for their own destiny, and identity.&lt;/p&gt;
&lt;p&gt;Used in a (mostly) harmless way it's used to sell things to people
that can be "customised" to fit your "own personal style" (without
&lt;em&gt;really&lt;/em&gt; giving you any autonomy), whereas on a higher and more
sinister level it is used to justify the horrors of society.  As an
out of context Margaret Thatcher would say "there's no such thing as
society, only people".  After all, society is just men, women and
those damn enbies, that all make their own free choices, and if
society is bad, then that's just a representation of how people are
bad.&lt;/p&gt;
&lt;p&gt;This is an over-simplification of course, but it digs at the core of
what individualism means to us.  It's a way to absolve society of
guilt, up to refusing the existence of it all together.  Individualism
touches many, if not all aspects of society, and it would take too
long to really examine them all here.  Instead, I want to focus on
what this means for "the good place".&lt;/p&gt;
&lt;h2&gt;There is no society in "the good place"&lt;/h2&gt;
&lt;p&gt;I don't know if the word "society" is ever used in the script, but it
is certainly not a subject of conversation in any of the episodes.
None of the characters will acknowledge that there is a human society
or what it looks like.  The focus is on individuals.  After all, the
fact that the world is bad is the result of just a few bad people,
that need to become better.&lt;/p&gt;
&lt;p&gt;This is where the view that "there is no bad people" the show tries to
hammer into you falls flat.  Because it's a lie.&lt;/p&gt;
&lt;p&gt;Human society is structured in a way that a few select people at the
top have a lot of wealth and power, while the rest of us live in
varying degrees of poverty by comparison.  I grew up in Germany so I'm
gonna say I don't live in luxury and peace by comparison to others,
but we &lt;em&gt;all&lt;/em&gt; suffer under the ruling class.  This is a reality the
show refuses to acknowledge and it makes it's arguments about moral
philosophy feel almost dystopian.&lt;/p&gt;
&lt;p&gt;Maybe this is controversial, but there are bad people.  If it is your
job to harass homeless people, you are a bad person.  If it is your
job to enforce the "war on drugs" that overwhelmingly affects black
people, you are a bad person.  If you are a billionaire, you are a bad
person.  You are in a position where you &lt;em&gt;could&lt;/em&gt; change society for
the better. You &lt;em&gt;could&lt;/em&gt; give all your wealth away, and actually help
people.  But you don't.  And no, I don't mean the fake philanthropy
that rich people indulge in because those are usually just schemes to
pay less taxes and massage on their public image.  No billionaire ever
gives away so much money that they stop being a billionaire.&lt;/p&gt;
&lt;p&gt;The ending of the good place is framed as a beautiful thing where
everybody gets to live a life in heaven in the end, if they manage to
work on themselves to become better people.  And sure, there are "bad
people" like sexists and racists, and they'll just get stuck in these
tests forever that they won't escape until they become better people.
It doesn't matter how much suffering you've caused others, you get to
go to the good place if you manage to accept that you were bad.&lt;/p&gt;
&lt;h2&gt;Why an afterlife?&lt;/h2&gt;
&lt;p&gt;So I mentioned that in the show, the existence of an afterlife is
never explained, rationalised or called into question.  It exists in a
vacuum, the same way that people in it live in a vacuum.&lt;/p&gt;
&lt;p&gt;The ending of "the good place" is framed in a way that is meant to
make you feel happy and hopeful, but all it makes me feel is wonder
why we needed to wait until the afterlife for people to deserve
happiness.&lt;/p&gt;
&lt;p&gt;The world is an awful place because of people, sure, but it's the
system that makes people into monsters.  Not only will it corrupt
people going in with good intentions, it will turn people with bad
intentions into powerful rulers.&lt;/p&gt;
&lt;p&gt;"The good place" fails to or refuses to understand that society
exists, and portrays a moral system in which all actions are
unconnected from the bigger picture.  If you were a nice person to
people in person, and generally tried to be &lt;code&gt;g o o d&lt;/code&gt; then it doesn't
matter if your employees need to pee into bottles, or if your company
is burning the rainforest to ash.&lt;/p&gt;
&lt;p&gt;Hell, the ruthless business lady in the "medium place" was sent there
because she saved someone in her &lt;em&gt;last&lt;/em&gt; moment.  But the "bad things"
she did???  SHE WAS RUDE TO PEOPLE.  Don't worry the exploitation
through the capitalist machine, that's all fine.&lt;/p&gt;
&lt;h2&gt;The shape of art &amp;amp; paradise&lt;/h2&gt;
&lt;p&gt;To wrap up this article I want to at least mention why I'm writing
about this.  Because I said earlier that I didn't find the show
special, funny, or intentionally bad enough to really engage with it.
And now here I am, writing upwards of 2000 words about it :)&lt;/p&gt;
&lt;p&gt;The media we consume as people shapes us, and influences us in quite
profound ways.  The way we tell stories is symptomatic of how society
perceives itself, and how people see themselves in society.  Media
that doesn't acknowledge the existence of society then and the
suffering it brings will inevitably white-wash reality, and push this
influence on anyone consuming it.&lt;/p&gt;
&lt;p&gt;At this point I would have liked to mention a better show or movie, or
even book, but none really come to mind.  I guess it's hard to point
to any text and demand it delivers a coherent world philosophy, while
also being a story with characters and plot.&lt;/p&gt;
&lt;p&gt;As a society we need to grow the fuck up.  The stories we tell each
other of heroes and villains, the balance between good and evil
hanging in the balance, all while these actors exist outside of
anything that could be called a power hierarchy, needs to end.  Only
when we grow up from this world view can we realise that paradise is
within us, and that collectively we can create it here on earth.&lt;/p&gt;
&lt;p&gt;Not gonna lie though, trains that go through space are pretty cool.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Sun, 20 Sep 2020 00:00:00 +0200</pubDate><guid>tag:None,2020-09-20:/blog/the-good-place-vs-the-ethics-of-society</guid><category>Blog</category><category>culture</category><category>politics</category><category>philosophy</category></item><item><title>On gender, transition, and re-transition</title><link>/blog/on-gender-transition-and-re-transition</link><description>&lt;p&gt;It's pride month.  Which actually has nothing to do with this post,
but might have inspired me to write something.  Anyway, if you're
someone who doesn't like thinking about gender, and only follow me for
my &lt;em&gt;s p i c y / r u s t / t a k e s&lt;/em&gt;, maybe skip this one.  Also, if
you're a TERF and use any of these words to harm anyone, go choke on a
brick you fucking piece of human garbage.&lt;/p&gt;
&lt;p&gt;Cool, that's the disclaimers out the way.&lt;/p&gt;
&lt;h2&gt;The part that's all about me&lt;/h2&gt;
&lt;p&gt;I guess this is a kind of coming out: I'm trans!  I've been "on the
internet" for a while now, and have way too many people following me
than is reasonable for my boring life.  And I guess a lot of you might
not know this.  I've never made a point of it, and I know from
personal experience that people read my gender &lt;em&gt;very&lt;/em&gt; differently.&lt;/p&gt;
&lt;p&gt;Some timeline stuff I guess.  I'm not gonna do the "I've always been
trans" thing, because I know that's not true.  That being said that I
was quite miserable before my transition for a few different reasons I
won't get into right now.&lt;/p&gt;
&lt;p&gt;I started socially transitioning around 2011, then started HRT in
2013, and then...well, just kinda lived my life.  I'm not gonna sit
here and pretend that transition wasn't the correct thing for me to
do, and I am a much happier and well-rounded person now because of it.&lt;/p&gt;
&lt;p&gt;Why am I writing this?  Because after all I've been pretty happy just
being stealth (meaning not being public about my trans-ness) for a
while now.  And I'm not the kind of person who wants to share my
personal life all that much.  It's weird being on the internet when
everything you say is gonna be seen by thousands of people.&lt;/p&gt;
&lt;p&gt;Well...the reason is that my gender identity is changing.  Has
changed.  I guess I've always been a little butch, but in recent times
(meaning the last ~6 months or so) I've been feeling explicitly more
masculine.  I've wanted to go by he/him pronouns, wear different
clothes, express myself differently in public, grow a beard (something
I've always failed at lol).  It wasn't just that my idea of what being
a woman meant changed, I think fundamentally the way I related to my
gender changed.&lt;/p&gt;
&lt;p&gt;And this is where things become really complicated.&lt;/p&gt;
&lt;h2&gt;The part that's about society&lt;/h2&gt;
&lt;p&gt;The way that our society at large handles transgender discourse is
toxic.  From the very beginning of my coming out, there's been an
inscrutible focus on "why" people are trans.  There must be medical
reasons.  Look at this brain scan of this one transgender lady.  Her
brain looks like a cis ladies brain.  This will once and for all prove
that trans people are &lt;em&gt;trapped in the wrong body&lt;/em&gt;! ...&lt;/p&gt;
&lt;p&gt;I understand why this framing has come about and stuck, because it was
a great way for somewhat liberal people to convince more conservative
people that "no actually trans people are like...real, and not just
making it up".  This line of reasoning is called "trans medicalism"
and it's rooted in the idea that trans people are &lt;em&gt;scientifically&lt;/em&gt; the
gender that they say they are.&lt;/p&gt;
&lt;p&gt;This approach has several problems.  It is extremely oversimplifying,
and makes assumptions about the nature of gender that many people
would not agree with.  Worse, even the people who don't really believe
in it, who only use it as a weapon against the TERFs, to defend their
own identity, end up upholding the European gender model binary, one
that would rather many non-binary and even transgender identities
didn't exist in the first place.  It is a model that will never truly
accept you for being trans, only sort of tolerate you, because maybe
you're close enough to the status quo to fit in.&lt;/p&gt;
&lt;p&gt;And a lot of trans people start internalising trans medicalism as a
survival mechanism.  This is where this discourse becomes harmful.
Because not only does it prevent some trans people from actually
expressing their non-binary gender identities, now you have insecure
people who are threatened in their identity by the idea that there's
no medical truth to being trans, and bully people who don't conform to
this.&lt;/p&gt;
&lt;p&gt;Even worse, they will sometimes align themselves with TERFs to defend
the "true trans people", before "the younger generation ruined
everything".  And this is where this all comes back to me.&lt;/p&gt;
&lt;h2&gt;Gender isn't fixed&lt;/h2&gt;
&lt;p&gt;During the last few months I've been trying to find experiences by
people similar to me, and it made me very very scared.  I didn't
really know what to call myself.  Because I'm by no means a cis man,
but looking for people who "de-transitioned", I found a lot of people
who were hurting, who felt they had been pressured into transition,
and who were being rallied around by TERFs who thought these poor
souls proved their bullshit points of views.&lt;/p&gt;
&lt;p&gt;And I saw a lot of trans people yelling at any trans person even
considering "de-transitioning", as some kind of traitor.  I guess I
understand why.  You don't wanna be giving the TERFs more ammunition.
You don't want to undermine your own identity.  Maybe you don't really
believe in it, but your self esteem is built on trans-medicalism.  How
do you deal with people who de-transition?&lt;/p&gt;
&lt;p&gt;I'm still not really sure what I would call myself, because I think
de-transitioning is the wrong term for what I would want to do.  And
really, I think I'd like to think about it as just another section of
the life-long transition of my gender.  To live means to change, and
my gender will change until I die.  There's nothing I can do to stop
it, and I think trying to control it will inevitably fail.&lt;/p&gt;
&lt;p&gt;I think it's also important to point out again that I regret nothing.
I'm glad I've been living as a woman for close to 10 years.  I don't
know how I want to express my gender identity, or on what scale
neccessarily.  Maybe I'll use different pronouns with friends, maybe
only from time to time, maybe I'll change nothing in the end because
this is all "just some phase".&lt;/p&gt;
&lt;p&gt;But I think it brings me to the core point I want to make here:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stop pretending as if transitioning into a gender is the
end-all-be-all of your gender identity!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So what if something is a phase?  In my opinion it doesn't make it any
less valid.  Transition is a journey, not a means to an end.  And
transitioning to femme, and back to masc (MtFtM), or vice versa
doesn't make someone less trans.  How can people believe that gender
is a spectrum, while not accepting that people will move around on
this spectrum?&lt;/p&gt;
&lt;p&gt;The worst thing is: this is something I would have expected to explain
to my mum, but I didn't expect this to be such a controvertial thing
in the trans community itself.&lt;/p&gt;
&lt;h2&gt;Why write this?&lt;/h2&gt;
&lt;p&gt;I was thinking about writing this article for at least a few weeks
now.  And undoubtebly it'll be many days between writing it as a first
draft, and the finished thing on my website.  I revealed a lot of
personal things in this post, things that I wouldn't otherwise want to
share.&lt;/p&gt;
&lt;p&gt;I think ultimately I want to be a voice of support for anyone who's
feeling similarly to me: "older" trans people (I'm not even 30 lol),
who have been doing this "new gender" thing for so long that it became
normal, who might feel themselves wanting to either express themselves
in much more feminine or masculine ways than before, or at different
intensities, or more androgynously.&lt;/p&gt;
&lt;p&gt;I think it's important that we remind ourselves that transition isn't
a means to an end, that gender is ever changing, and normalising the
idea of re-transition.  And this doesn't just apply to cis people!
Trans people carry the trauma of society with them and can be just as
toxic in this matter as the TERFs.&lt;/p&gt;
&lt;p&gt;Life is too complex for anything to remain the same forever.  We all
need to become better at embracing this.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Thu, 18 Jun 2020 00:00:00 +0200</pubDate><guid>tag:None,2020-06-18:/blog/on-gender-transition-and-re-transition</guid><category>Blog</category><category>/dev/diary</category><category>culture</category><category>gender</category></item><item><title>Rust, or: how to run a community</title><link>/blog/rust-or-how-to-run-a-community</link><description>&lt;p&gt;This will very much be an off the cuff post about community building
with insights that I've seen from various communities I was a part of
in the last 10 years.  None of this is to be taken as facts, and is
entirely personal opinion.  I do hope however that this post might
make one or the other think about how we run communities.
Really… I'm just bored and want to write something.&lt;/p&gt;
&lt;p&gt;The communities I've been a part of involve Rust, Fedora, Moonscript
(a lua coffee script type), libgdx (a Java game framework), Nix(OS),
and the Homeworld 2 modding community that's to blame for me learning
to code and unleashing my terrible puns on the world.&lt;/p&gt;
&lt;p&gt;There seem to be two avenues of community organising: centralisation
and distribution.  One favours building a community around a shared
name, domain, communication channel, and workflow.  People work on the
same things, in the same place, under the same name.  This can work
really well for smaller projects, and generally means less friction
when people from different backgrounds have to talk to each other,
because everybody is kinda in the same place.  This is how most
communities get started, and how Rust was working until about one year
ago.&lt;/p&gt;
&lt;p&gt;There is a fundamental problem with this model though: at some point
your community will become too big, and people will start to fracture
out into their little bubbles.  There's no fixed point at which this
happens, but it seems to happen sooner or later for most projects.&lt;/p&gt;
&lt;p&gt;I think as community builders it is our job to embrace these
fractures, letting sub teams spin off into their own little ventures,
while using the shared name to advertise these ventures.  I think it's
okay to not have a project represent as a closed front to outsiders,
but very much embracing the fact that projects are run by many
individuals that chose to collaborate on something larger than
themselves.&lt;/p&gt;
&lt;p&gt;The reason why I'm such a big fan of &lt;a href="https://spacekookie.de/blog/collaborating-with-git-send-email/"&gt;e-mail collaboration&lt;/a&gt; via
mailing lists (both for conversations and sending patches) is that it
encourages this separation.  A project that forces people who
cross-collaborate to jump from tool to tool is just as centralised as
a project that only has a single communication channel.  But there's
definitely examples of projects that have grown into little bubbles
that still work on a shared "product", without having to all do it in
the same place: the Linux kernel.&lt;/p&gt;
&lt;p&gt;Whether you agree or disagree with my take on e-mails, I think we
should all be aware of the finite size that a community can have.  And
at what point should we start to embrace community mitosis?&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Wed, 08 Apr 2020 00:00:00 +0200</pubDate><guid>tag:None,2020-04-08:/blog/rust-or-how-to-run-a-community</guid><category>Blog</category><category>free software</category><category>culture</category><category>politics</category></item><item><title>So there's a pandemic</title><link>/blog/so-theres-a-pandemic</link><description>&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; this article was written as is, but never published.  I
decided to retro-actively publish it because I felt it was important
to have it in my log of articles, but I also don't think I can really
add much more to this now since the political climate has shifted
quite hard.)&lt;/p&gt;
&lt;p&gt;I've been meaning to publish this article a lot sooner, but here we
are.  The last month has been kinda bonkers.  Reading this in the
future might feel either funny or wistful.  Reading this in the now
must feel redundant.&lt;/p&gt;
&lt;p&gt;Anyway, I've been working on a few things, and also have been thinking
about a few blog posts that I've wanted to write.  (One has already
gone up, so once again I'm a literary genius with getting my ordering
right).  I'll try to write a bit more, and care less about each
article being as polished as previously.  I feel like I've said this
before, so I'll try not to become &lt;em&gt;too&lt;/em&gt; spammy.  There's still
Twitter…&lt;/p&gt;
&lt;p&gt;In this pandemic I've seen a lot of rhetoric mirror the security
discourse post 9/11.  Additional restrictions on public life are being
advocated for, because they will save lives.  Checkpoints, new rules
and regulations, everybody has an opinion on how things should be
running and very frequently run to the state to enforce anything
"health officials" say might work.&lt;/p&gt;
&lt;p&gt;Ultimately this virus is the perfect threat: you can't see it, you
don't even know if you have it, you can endanger people by moving
around freely.  And there will never again be a time when "but what
about a virus" won't bu used to justify restrictions on the lives of
people.&lt;/p&gt;
&lt;p&gt;And please don't interpret me saying these things as there being some
conspiracy to enact authoritariasism, as much as that sounds like a
novel you'd read, that's not how the world works.  This isn't
plotting, it's simple fascist opportunism.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Thu, 02 Apr 2020 00:00:00 +0200</pubDate><guid>tag:None,2020-04-02:/blog/so-theres-a-pandemic</guid><category>Blog</category><category>culture</category><category>politics</category></item><item><title>Collaborating with git-send-email</title><link>/blog/collaborating-with-git-send-email</link><description>&lt;p&gt;There's is a conversation that I keep having with various people, and
while some of my thoughts are available in e-mail threads on my
&lt;a href="https://lists.sr.ht/~spacekookie/public-inbox/%3C87woa41sgn.fsf%40kookie.space%3E"&gt;public-inbox&lt;/a&gt;, I felt like maybe it was time to write a blog post
about it as well.&lt;/p&gt;
&lt;p&gt;The reason for this is that there is documentation on the internet on
how to use git-send-email in theory, but few ever really talk about
the resulting workflow beyond a single patch.&lt;/p&gt;
&lt;p&gt;I won't pretend that the tools couldn't use some work or that it
doesn't take a bit of getting used to, but the reward is well worth
it, and something that I feel deserves more attention.&lt;/p&gt;
&lt;p&gt;At the end of this I will talk a bit about why I think this mode of
collaboration is good, and could potentially be better than existing
collaboration models.&lt;/p&gt;
&lt;h2&gt;The basics&lt;/h2&gt;
&lt;p&gt;To get into the basics of sending patches by email, I recommend
&lt;a href="https://git-send-email.io"&gt;git-send-email.io&lt;/a&gt;, which goes into the setup of basics on various
platforms.  It's one of those things where your setup will vary
slightly, depending on your OS and email hoster, and not something
that I feel needs too much more explanation.&lt;/p&gt;
&lt;p&gt;You can go through that set of slides to send a test patch to the
project that's hosted on sourcehut to see if your setup is working
properly.  This is enough to send short one-offs to projects without
having to make an account anywhere (except the e-mail you already have
anyway).&lt;/p&gt;
&lt;h2&gt;Discussion and patches&lt;/h2&gt;
&lt;p&gt;I think one of the main advantages of git mail collaboration is that
the workflow of sending patches and creating meaningful discussion on
patches is so interlinked.  While you are using different clients to
send patches and replying to feedback, the code that you send is still
available in your e-mail client. So it's easy to reply to both
feedback, while copying parts of a patch for reference.&lt;/p&gt;
&lt;p&gt;It's important here to send e-mail as plain text, because otherwise it
might cause problems for people to reply to.  There's a great website
that helps you make sure your e-mail client can and is configured to
use plain text: &lt;a href="https://useplaintext.email/"&gt;useplaintext.email&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Patchsets and revisions&lt;/h2&gt;
&lt;p&gt;So having the basics out the way, I think it's important to discuss a
more complete workflow.  When people send contribtions to projects
using pull-requests, often a set of changes will go through several
revisions before getting merged.  It's also nice to quickly force push
to fix a small typo or similar without having to let that typo ever be
part of the history of the commits that get merged.&lt;/p&gt;
&lt;p&gt;When collaborating with git over e-mail this is still possible via
"revisions".  When sending a patchset, you can provide a &lt;code&gt;-v&lt;/code&gt;
parameter with a number.  The patches you send will then have a
revision number in them, as follows: &lt;code&gt;[PATCH v2]&lt;/code&gt;.  It's recommended
to send newer revisions of your patchset as a reply to the previous
one, i.e. &lt;code&gt;[PATCH]: foo&lt;/code&gt; being the parent of &lt;code&gt;[PATCH v2]: foo&lt;/code&gt; in the
same thread.&lt;/p&gt;
&lt;p&gt;If you get replies to your patch, you can make changes to your
commits, then send out a new revision to the whole set, or just
individual patches, if your set of changes contains a lot of code and
you want to keep the volume of e-mails down.&lt;/p&gt;
&lt;p&gt;The advantage of this is both that people can comment on things as
they happen in the history of the code instead of being forced to
understand a set of changes all in one go, and that you are
automatically encouraged to squash commits with messages like "small
fixes" before sending them out to a project's mailing list.&lt;/p&gt;
&lt;h2&gt;Cover letters&lt;/h2&gt;
&lt;p&gt;One neat thing that many people also don't know about are cover
letters.  Sometimes a set of changes is so large and requires some
preface to make sense, it's a good idea to write an introduction for
someone to read first.  This is what GitHub pull-request descriptions
were derived from.&lt;/p&gt;
&lt;p&gt;To generate a cover letter you need to create your patches in two
stages:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;git format-patch&lt;/strong&gt; to generate a series of &lt;code&gt;.patch&lt;/code&gt; files that can
later be turned into e-mails.  This tool takes a &lt;code&gt;--cover-letter&lt;/code&gt;
paramenter that indicates to it to generate an empty patch called
&lt;code&gt;0000-cover-letter.patch&lt;/code&gt;, which contains the diff-stat (git-shortlog) of
your proposed changes.  You are then free to edit this file in your
favourite text editor to write a friendly introduction to your
patchset.&lt;/p&gt;
&lt;p&gt;Another often overlooked feature here is "timely commentary", are
comments in the patch e-mail that won't be part of the patch or the
commit message itself.  They can be made after the &lt;code&gt;---&lt;/code&gt; marker in a
patch mail, but before the actual patch starts.  This section is
usually used for the diff-stat of that particular patch.&lt;/p&gt;
&lt;p&gt;After that you can use &lt;strong&gt;git-send-email&lt;/strong&gt;, almost the same as before,
but instead of giving it a series of commits to send (say &lt;code&gt;HEAD~3&lt;/code&gt;),
you now just say &lt;code&gt;*.patch&lt;/code&gt; or wherever you saved the patch files
earlier.&lt;/p&gt;
&lt;p&gt;You don't have to resend the cover letter every time you send a new
revision of your whole patchset.  On the other hand, if things have
fundamentally changed, it might be a good idea to add one again, just
to make sure it's up to date for new people joining the thread for
feedback.&lt;/p&gt;
&lt;h2&gt;An example&lt;/h2&gt;
&lt;p&gt;I always work well with examples and I think it's good to illustrate
how all of this can work, especially for people who might be scared by
the concept of collaborating this way.&lt;/p&gt;
&lt;p&gt;I'm creating some patches for my &lt;code&gt;libkookie&lt;/code&gt; repo and I want to get
some feedback from myself, so I decide not to push to master, which I
totally could do, but to my public-inbox instead.&lt;/p&gt;
&lt;p&gt;There's two commits that I want some feedback on, so I make my
commits, and verify that they are indeed what I want them to be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;❤&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;libkookie&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="mf"&gt;2.&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;a147c15e998d57d9db877c9cd92d0cf04411cc9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;Author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Katharina&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;Wed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Jan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;06&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nl"&gt;kitty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmux&lt;/span&gt;

&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d54937fa9414d87971a01dbc0dec5105b97e8f7e&lt;/span&gt;
&lt;span class="nl"&gt;Author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Katharina&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;Wed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Jan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;adding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gpg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;submodule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Well, perfect.  This way I can also verify that the sometimes
confusing range syntax in git (&lt;code&gt;HEAD~2..HEAD&lt;/code&gt;, meaning all commits
&lt;code&gt;HEAD~2&lt;/code&gt;, so 2 commits ago, and &lt;code&gt;HEAD&lt;/code&gt;, so now) works the way I'm
expecting it to.&lt;/p&gt;
&lt;p&gt;I think this is quite an impressive set of changes so I decide to
reward myself with a good ol' cover letter.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt; ❤ libkookie&amp;gt; git format-patch --cover-letter HEAD~2..HEAD
0000-cover-letter.patch
0001-ws-adding-gpg-submodule-by-default.patch
0002-ws-kitty-setting-default-shell-to-tmux.patch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I can go and verify the patches look okay, do a final pass over the
typos and then edit the cover letter as well:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;From&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;a147c15e998d57d9db877c9cd92d0cf04411cc9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2001&lt;/span&gt;
&lt;span class="k"&gt;From&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Katharina&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Wed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Jan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;06&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;
&lt;span class="nl"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PATCH 0/2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;patchset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;universe&lt;/span&gt;

&lt;span class="k"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;whom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;may&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;concearn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;have&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;magnificent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;
&lt;span class="n"&gt;universe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;really&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;think&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;merge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;because&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;otherwise&lt;/span&gt;
&lt;span class="n"&gt;you&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;Cheers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;


&lt;span class="n"&gt;Katharina&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;adding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gpg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;submodule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nl"&gt;kitty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmux&lt;/span&gt;

&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;workstation&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nix&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;workstation&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kitty&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kitty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++-&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;changed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;insertions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- &lt;/span&gt;
&lt;span class="mf"&gt;2.24.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Perfect, they'll just love that over at spacekookie inc.  I quickly
exit, save, and close the file and send off the patches:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;❤&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;libkookie&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--To &amp;quot;~spacekookie/public-inbox&amp;quot;@lists.sr.ht *.patch &lt;/span&gt;
&lt;span class="mi"&gt;0000&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patch&lt;/span&gt;
&lt;span class="mi"&gt;0001&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;adding&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;gpg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;submodule&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patch&lt;/span&gt;
&lt;span class="mi"&gt;0002&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;kitty&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;setting&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tmux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patch&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mbox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Adding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Katharina&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;From: Katharina Fey &amp;lt;kookie@spacekookie.de&amp;gt;&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;From&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Katharina&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;To&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;spacekookie&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="nv"&gt;@lists&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ht&lt;/span&gt;
&lt;span class="nl"&gt;Cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Katharina&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nl"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PATCH 0/2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;patchset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;universe&lt;/span&gt;
&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Wed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Jan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;
&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mf"&gt;20200115211050.31664&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;Mailer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.24.1&lt;/span&gt;
&lt;span class="n"&gt;MIME&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;
&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Transfer&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="nc"&gt;bit&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Cc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;above&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;been&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;expanded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;additional&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;addresses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;By&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prompts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;before&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sending&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;whenever&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;occurs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;behavior&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;controlled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sendemail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confirm&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;additional&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;information&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;git send-email --help&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;retain&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;behavior&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;but&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;squelch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;git config --global sendemail.confirm auto&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;Send&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="vm"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="n"&gt;es&lt;/span&gt;&lt;span class="o"&gt;|[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;|[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="n"&gt;dit&lt;/span&gt;&lt;span class="o"&gt;|[&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="n"&gt;uit&lt;/span&gt;&lt;span class="o"&gt;|[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can get the question about the Cc not to show up by providing
&lt;code&gt;--supress-cc all&lt;/code&gt; as a parameter, but I find it useful.  Basically a
Cc is just a ping, and if you're mentioning people by e-mail address
in your patchset (for example, if you have &lt;code&gt;Co-Authored-By&lt;/code&gt; lines in
there) the appropriate people can be pinged for you automatically.&lt;/p&gt;
&lt;p&gt;So, I'm happy with things as they are, so I hit "a", for all and send
off all three e-mails.  (You can find them in the archive
&lt;a href="https://lists.sr.ht/~spacekookie/public-inbox/%3C20200115211246.1832-1-kookie@spacekookie.de%3E"&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I wait, drink some chocolate oat milk, and wait for a reply.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Katharina&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ago&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nl"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;Re&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PATCH 2/2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nl"&gt;kitty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmux&lt;/span&gt;
&lt;span class="k"&gt;To&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;spacekookie&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="nv"&gt;@lists&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ht&lt;/span&gt;
&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Wed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Jan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;

&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--- a/modules/workstation/kitty/kitty.conf&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;workstation&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kitty&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kitty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@@&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@@&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;font_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;font_familt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;twemoji&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;font&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;font_family&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;twemoji&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;font&lt;/span&gt;

&lt;span class="n"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;was&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;typo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;before&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;but&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;think&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;we&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;don&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t really want this feature&lt;/span&gt;
&lt;span class="s1"&gt;anymore, because all the font integration stuff is broken anyway.  I&lt;/span&gt;
&lt;span class="s1"&gt;think it&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;better&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;again&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;
&lt;span class="n"&gt;becomes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;relevant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;again&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What's interesting is how feedback can be layered into the patch
itself, to comment on changes that need to be made.  This way it's
possible to keep track of the relevant lines of code, and also be able
to have a threaded conversation.&lt;/p&gt;
&lt;p&gt;I guess I have a fair point here, the emoji fonts have been broken on
my computer for ages. So while I'm somewhat annoyed by having to
change things again, I can also understand why.&lt;/p&gt;
&lt;p&gt;What I want to do now is reply with only a second revision on this one
commit because I don't know if there's more feedback coming for the
rest of the patchset.  First, we need to figure out what the
&lt;code&gt;Message-Id&lt;/code&gt; of the previous reply is, either via you e-mail client,
or the public mail archive of the project.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: this can sometimes be tricky, but usually you should be able
to see the "raw" message in most mail clients to find the &lt;code&gt;Message-Id&lt;/code&gt;
of the e-mail you care about.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;❤&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;libkookie&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;--To &amp;quot;~spacekookie/public-inbox&amp;quot;@lists.sr.ht \&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;--reply-to &amp;quot;&amp;lt;87r2001k7k.fsf@kookie.space&amp;gt;&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;OK&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;says&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="nl"&gt;Sendmail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nix&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;msmtp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;spacekookie&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="nv"&gt;@lists&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ht&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;
&lt;span class="k"&gt;From&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Katharina&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;To&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;spacekookie&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;inbox&lt;/span&gt;&lt;span class="nv"&gt;@lists&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ht&lt;/span&gt;
&lt;span class="nl"&gt;Cc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Katharina&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nl"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PATCH&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nl"&gt;kitty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmux&lt;/span&gt;
&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Wed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Jan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;0000&lt;/span&gt;
&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mf"&gt;20200115214256.1770&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;kookie&lt;/span&gt;&lt;span class="nv"&gt;@spacekookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;Mailer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.24.1&lt;/span&gt;
&lt;span class="ow"&gt;In&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Reply&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;To&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;87&lt;/span&gt;&lt;span class="n"&gt;r2001k7k&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsf&lt;/span&gt;&lt;span class="nv"&gt;@kookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;space&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;References&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;87&lt;/span&gt;&lt;span class="n"&gt;r2001k7k&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fsf&lt;/span&gt;&lt;span class="nv"&gt;@kookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;space&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;MIME&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;
&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Transfer&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="nc"&gt;bit&lt;/span&gt;

&lt;span class="k"&gt;Result&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The way that the reply works mean the thread now looks somewhat like
this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;patchset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;universe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;↳&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;adding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gpg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;submodule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;↳&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kitty&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmux&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;↳&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Re&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kitty&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmux&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="err"&gt;↳&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kitty&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmux&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I wait a bit longer and I get another e-mail thanking me for my
contributions, and saying that the patches have been merged.&lt;/p&gt;
&lt;p&gt;Sometimes it can be nice to re-generate a patchset with all the latest
versions of patches, even if they've been sent to the list before,
just to make it easier to apply them.  But that's often also not
required.&lt;/p&gt;
&lt;h2&gt;The conclusion&lt;/h2&gt;
&lt;p&gt;Hey, you made it all the way to the end of this post, congrats!&lt;/p&gt;
&lt;p&gt;I think the way of collaborating I outlined in this post has a lot of
advantages over currently popular models (i.e. pull-requests on GitHub
or merge-requests on GitLab).  People talk about wanting to
decentralise development, escaping these walled gardens that companies
have built, and they often disagree on how this can best be done.&lt;/p&gt;
&lt;p&gt;There's even people who gladly opt into this model because they feel
that the added gamification of the platform will get people to work
more.  Not only do I think that the relationship that people have with
maximising a number on a website can be abusive, but also that I've
felt better getting patches into projects via a mailing list than any
PR has ever made me feel.&lt;/p&gt;
&lt;p&gt;I'm not gonna pretend that the tooling for all of this couldn't use
some work: git-send-email has 1000 confusing options and also getting
the &lt;code&gt;Message-Id&lt;/code&gt; to reply to patches with can be hard and annoying.&lt;/p&gt;
&lt;p&gt;In fact, I'm working on some tools to make both sending and applying
patches easier (as part of the &lt;a href="https://git.sr.ht/~spacekookie/dev-suite/"&gt;dev-suite&lt;/a&gt; project started by my
friend Michael.  I'll write more about this soon!)&lt;/p&gt;
&lt;p&gt;In this model of development there's no need for a central service
like GitHub, no need for special software to make pull-requests
federate or even for you to host a copy of the project anywhere.&lt;/p&gt;
&lt;p&gt;All you need is the code the project provided you, a text editor and a
mail address.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Thu, 16 Jan 2020 00:00:00 +0100</pubDate><guid>tag:None,2020-01-16:/blog/collaborating-with-git-send-email</guid><category>Blog</category><category>/dev/diary</category><category>git</category><category>email</category></item><item><title>Some website design changes</title><link>/blog/some-website-design-changes</link><description>&lt;p&gt;Howdy, it's that time of year again where I apparently do design
things on this website (the last article is from exactly 2 years ago).
Apologies if you've never been to my website and only use the &lt;a href="https://spacekookie.de/rss.xml"&gt;RSS&lt;/a&gt;
feed.  Also: you're cool!&lt;/p&gt;
&lt;p&gt;In previous iterations of this series I tended to fundamentally change
the way that the website worked, either by changing the way that the
html was generated, or by cutting down/ adding categories.  This time
I'm doing none of that.&lt;/p&gt;
&lt;p&gt;Indeed things are getting simpler but mostly on the CSS side of
things.  I was able to delete about half of my CSS which is a pretty
cool.  The biggest change in the way the website looks is the article
overview and the article pages themselves.&lt;/p&gt;
&lt;p&gt;Generally I didn't like the card design style very much anymore so I
wanted to change that.  But I also wanted to make it simpler to see
all my articles at a glance, without any summaries.  I feel this makes
the blog feel more "web log-y", which I like.  It also means it's now
consistently bright text on dark background and I think I've gotten
the typography down enough to make it all pretty.&lt;/p&gt;
&lt;p&gt;Anyway, there's more things I wanted to do but those will come later.
I should also point out that my primary code host for this website
isn't github anymore.  It's now hosted on &lt;a href="https://git.sr.ht/~spacekookie/website"&gt;sourcehut&lt;/a&gt; and
collaborations are still welcome (if you see a typo or have general
comments), albeit not with pull requests anymore. You can submit
patches to my &lt;a href="https://lists.sr.ht/~spacekookie/public-inbox"&gt;public inbox&lt;/a&gt; which I have hinted at in a previous
article.&lt;/p&gt;
&lt;p&gt;In post-congress news I seem to have caught a cold, so: bye.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;curl up in bed&lt;/em&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Fri, 03 Jan 2020 00:00:00 +0100</pubDate><guid>tag:None,2020-01-03:/blog/some-website-design-changes</guid><category>Blog</category><category>/dev/diary</category><category>meta</category></item><item><title>Another decade down the drain</title><link>/blog/another-decade-down-the-drain</link><description>&lt;p&gt;Now that the last decade is officially over, there's some things I
want to write about. I do this less so for others, and more for
myself.  Around this time of year, people usually make new year's
resolutions, which is not quite what this is.  Instead, I want to
reflect on what the last ten years have meant for me, and some plans I
have for the next decade.&lt;/p&gt;
&lt;p&gt;I graduated school in 2011, started uni twice, dropped out twice (for
consistency), and found computer science and programming as my
passion.  I moved to Berlin, worked many jobs, at a bunch of different
companies and finally, towards the end of this year, made myself
independent as a freelancer.&lt;/p&gt;
&lt;p&gt;Why am I mentioning any of this?  Well, I don't think it's really
possible to plan for the future, so I won't try.  Instead, I want to
set myself a goal for the next ten years.  Something that has nothing
to do with my career, or even a hobby that I hold right now. But let
me back up a bit…&lt;/p&gt;
&lt;p&gt;Over 15 years ago (oof) I did an exchange program, which had me living
in France for six months.  During this time I became pretty fluent in
French.  Over time, unfortunately I forgot a lot of it again.  Then,
over the last few years I started learning a few other languages,
apart from English and German (I consider myself bilingual). I am
conversational in French and Esperanto, and can understand a few words
of Russian.&lt;/p&gt;
&lt;p&gt;So what's my goal for 2030?  Easy: I want to learn ten languages well.
This includes becoming fluent in the languages I already know
partially (French, Esperanto, Russian), as well as learning a few new
languages entirly.  Some that I am interested in are Arabic, Catalan,
Spanish, Scottish Gaelic and Kurdish.  I don't know if it will be this
exact set that I will end up learning, but it's a good starting point.&lt;/p&gt;
&lt;p&gt;Most importantly, I think that a decade is enough time to undertake
this venture.  I don't know where I will be in ten years, or what I'll
be doing and neither do I think that it's ever really possible for me
to guess.  But whatever my life looks lke, I hope that I'll be
speaking a lot more languages.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Wed, 01 Jan 2020 00:00:00 +0100</pubDate><guid>tag:None,2020-01-01:/blog/another-decade-down-the-drain</guid><category>Blog</category><category>/dev/diary</category></item><item><title>Part 1: Against Primitivism</title><link>/blog/part-1-against-primitivism</link><description>&lt;p&gt;This is the first of two blog posts that will be slightly more
philosophical than other texts on my blog.&lt;/p&gt;
&lt;p&gt;For some of my regular readers this thesis might not be particularly
radical, but I still feel like it warrants being said.&lt;/p&gt;
&lt;h2&gt;What is primitivism?&lt;/h2&gt;
&lt;p&gt;I think this is the most important question to ask and one that has
many answers. Depending on who you ask, and what their political
background is, the answer might be "a joke", or even "a slur".&lt;/p&gt;
&lt;p&gt;In simple terms, primitivism yearns to return to a simpler time,
removing technology from human lives as much as possible. This is
meant to address one of the largest sources of anguish and anxiety in
our modern society, removing it from the equation. In many places
primitivism even frames itself as revolutionary.&lt;/p&gt;
&lt;p&gt;The problem with this analysis is that it is inherently linked with
privilege. This can take many forms. A mild form would seek to abolish
the internet, personal computers and phones, arguing that letting
people return to real-life communities will result in more happiness
and a more "natural" life.&lt;/p&gt;
&lt;p&gt;This fails to acknowledge that these technologies are life saving for
many, giving both social outcasts and various disabled people a space
to have a community.&lt;/p&gt;
&lt;p&gt;But most often it is not those affected who make the case for these
measures. Usually it is white, able bodied men that fail to understand
how their perception of society is skewed because of their own biases.&lt;/p&gt;
&lt;p&gt;An even more extreme form of primitivism would reject more general
technological advancements, arguing for things to be "good" because
they are "natural". This analysis, even more so than the last, ignores
challenges that those who propose these solutions don't have to deal
with: what about medicine, what about artificial aids?&lt;/p&gt;
&lt;h2&gt;Against the internet&lt;/h2&gt;
&lt;p&gt;It is true, that in the modern world technology has been turned
against us. Large companies control the way that people interact with
technology, track them, and more. While it is possible to live outside
of this system, only a few people actually do. Even a lot of
technologists (software developers, hackers, ...) don't fully manage
to decouple themselves from the corporately controlled tech
bubble. i.e. how many hackers use Google, Twitter, etc.&lt;/p&gt;
&lt;p&gt;On some level it is understandable that the narrative of primitivism
has emerged. This is not to say that these ideas are in any way new,
but in a way they are making a comeback in certain leftist circles.&lt;/p&gt;
&lt;p&gt;For someone who doesn't know how to code or has only minor technical
literacy, this fight might seem lost. Approaches like the one
previously outlined seem welcome. I feel it is important to point out
though that the demographic of people coming to this conclusion is
already skewed. More vulnerable people that are dependent on
technology have a different analytical framework and come to radically
different solutions (more on that in a future post)&lt;/p&gt;
&lt;p&gt;It is this narrative that inspired these posts, at least in part. I
feel that to proclaim to "blow up the internet" (for example) is lazy
and counter revolutionary at it's core. It frames all conversation
about improving technology and using it in our struggles to liberate
ourselves as regressive, and somehow collaborative with an abusive
system. Suddenly instead of talking about strategy to our solutions
you are thrust to justify your work to people who misunderstand it's
basis and see it as part of the thing you are trying to fight.&lt;/p&gt;
&lt;h2&gt;Misunderstanding technology&lt;/h2&gt;
&lt;p&gt;So what do I mean by that, and do I have an example? I'm not trying to
say that someone has to be a programmer to critique technology. I'm
arguing that the same level of engagement people would expect of
someone doing art criticism be extended to tech.&lt;/p&gt;
&lt;p&gt;There is this notion that computers are fundamentally flawed, not
because they are fallible and replicate a human's biases, but because
of their foundational inner workings: binary! The sheer fact that
computers operate on the basic assumptions of truths and falsehoods
means that there is to assume to &lt;em&gt;be&lt;/em&gt; universal truths.&lt;/p&gt;
&lt;p&gt;Not only are conclusions from this hypothesis often shallow and
reductionist, they also misunderstand the performative,
interpretational nature of computers. On the wire every signal is
analog. It is the translation to binary that gives them meaning. But:
this does not mean it is representative of a truth, it is merely a
projection of an assumption. The same way that axioms in mathematics
are not "truths", but rather assumptions to build discoveries on top
of.&lt;/p&gt;
&lt;p&gt;The same can be applied to binary data: on the wire all data looks
pretty much the same. Again, it is an interpretation that turns
something into a text or a picture. There is no truth to data, only
relative perspective.&lt;/p&gt;
&lt;p&gt;Computers are indeed fallible and as flawed as the humans using
them. But this is precisely because there is no underlying truth to
computing, only the interpretations of those who make the
instructions. This is why I argue that machines are merely an
extension to ourselves rather than any "autonomous" system.&lt;/p&gt;
&lt;p&gt;I say "autonomous" (in quotes) systems, because it is another term
that is deeply misunderstood. But this time it is because the creators
of these systems want it to be misunderstood. This is what the next
essay will cover.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Sun, 24 Nov 2019 00:00:00 +0100</pubDate><guid>tag:None,2019-11-24:/blog/part-1-against-primitivism</guid><category>Blog</category><category>culture</category><category>technology</category><category>anarchy</category></item><item><title>Rust 2020: the RFC process and distributions</title><link>/blog/rust-2020-the-rfc-process-and-distributions</link><description>&lt;p&gt;I must have missed an e-mail in my inbox, because recently I started
seeing people publish Rust 2020 blogposts so I thought, why not. I
haven't been incredibly involved in the development of Rust in the
last few months, (navigating the delicate balance of being self
employed, working on free software and not burning out) but I feel
like that might change again. And also, I still have &lt;em&gt;feelings about
software&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This post was also largely inspired by my friend &lt;a href="https://xampprocky.github.io/public/blog/rust-2021/"&gt;XAMPPRocky's post&lt;/a&gt;,
as well as attending &lt;a href="https://2019.nixcon.org/"&gt;NixCon&lt;/a&gt; a few weeks ago, and generally
interacting with the NixOS RFC process.&lt;/p&gt;
&lt;h2&gt;What even is an RFC?&lt;/h2&gt;
&lt;p&gt;An RFC, or "request for comments" is a mechanism by which a group of
people can get feedback from a wider community on proposed
changes. The idea is that a written proposal outlines a change's
scope, implementation details, rationale and impact on the ecosystem,
then people make comments on the proposal. Usually by the time that
everybody has stopped shouting at each other, the RFC is ready to be
merged, meaning it is accepted and its vision can be implemented.
This can either be implementing a feature, or removing &lt;code&gt;unstable&lt;/code&gt;
flags from it.&lt;/p&gt;
&lt;p&gt;Unfortunately I'm not being too flippant here: the procedure of how an
RFC goes from "proposed" to "accepted" is very vague and can depend on
&lt;em&gt;a lot&lt;/em&gt; of factors. Needless to say, this can also be the source of a
lot of conflict in a community.&lt;/p&gt;
&lt;p&gt;Rust has had an RFC process for a few years now, and most, if not all
decisions to the language and ecosystem have gone through it, and the
community feedback it entailed. Some go largely overlooked, like &lt;a href="https://github.com/rust-lang/rfcs/pull/2376"&gt;this
one&lt;/a&gt; that I co-authored at the Rust All Hands 2018 in Berlin
(it's fine, I understand), others get hundreds of comments. This often
results in no meaningful conversations, in large parts because it's
hard to have a discussion with 1000 people, and in other part because
GitHub is a &lt;em&gt;terrible&lt;/em&gt; platform to do anything on (sequel hook).&lt;/p&gt;
&lt;h2&gt;RFC chaos&lt;/h2&gt;
&lt;p&gt;I remember this issue first coming up in the module refactoring
debates and the three (?) RFCs that were in total created before
everybody felt happy enough about it. These were the first large RFCs
I witnessed while being kinda part of the community. Many of the
people who were involved in them talked about how stressful it had
been and I think they might also be the first time that the RFC
process, the way that the Rust project implemented it, started showing
limitations of scale.&lt;/p&gt;
&lt;p&gt;The fact that an RFC is proposed, with no real structure or framework
on how to continue afterwards means that either feedback is chaotic
and iterations on the design can seem arbitrary, or on the other hand
some RFCs remain open for years, in limbo, where nothing really
happens on them. Both aren't great outcomes, only add to stress levels
of the people who were involved in writing them, and generally just
slows down our decision making process.&lt;/p&gt;
&lt;p&gt;As XAMPPRocky wrote in her blog post:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When 1.0 launched there was ~30 members of The Rust Programming
Language, now in 2019 we have ~200 members. This is nearly 7x the
amount of members, yet we've changed very little to be able to adapt
to this growth.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While she was talking about how many people get paid for Rust, I feel
this is also applicable to the way that we make decisions. Many people
wrote about the RFC process for their Rust 2019 posts in rather vague
terms, including &lt;a href="https://spacekookie.de/blog/rust-2019-how-we-make-decisions/"&gt;myself&lt;/a&gt;. Well, I'm mentioning it again,
because I feel like we should try something concrete.&lt;/p&gt;
&lt;h2&gt;Shepherds and an RFC committee&lt;/h2&gt;
&lt;p&gt;The NixOS project has two concepts in their RFC process which I think
are valuable and that the Rust project would benefit from: RFC
Shepherds and the RFC steering committee.&lt;/p&gt;
&lt;p&gt;The RFC steering committee is a group of between 5-6 people, assigned
for a year to oversee any new RFC, make sure that shepherds get
assigned to it, and also keep tabs on progress that is being made. Are
shepherds regularly (in whatever interval they deem appropriate)
meeting to discuss the RFC, is feedback being taken into account by
the authors, and how is the discussion generally going?&lt;/p&gt;
&lt;p&gt;They &lt;em&gt;do not&lt;/em&gt; need to actually understand where the discussion is
heading, but make sure that a discussion is happening. This would
solve the problem of RFCs remaining open for years, without getting
any further feedback and un-cluttering the PRs page of open RFCs. RFCs
that were forgotten about by their authors or that the community has
largely moved on from can be closed/ rejected. It can also give
closure to people who have written RFCs that was never rejected, but
not accepted either (again, I'm cool, don't worry).&lt;/p&gt;
&lt;p&gt;RFC shepherds are then assigned to an RFC (3-5 people) to actually
oversee the discussion and consolidate feedback into changes that can
be made on the RFC. They are also responsible for regular (again, up
to them how regular) meetings discussing the wider implications, as
well as small details of an RFC, usually on a video call, taking notes
for people who can't attend to read up on afterwards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An important note here:&lt;/strong&gt; shepherds don't have to be part of a team that
would otherwise oversee the development of a feature (like lang or
compiler) and instead can be any community member who feels like
nominating themselves or who is nominated by someone else. The idea is
that &lt;em&gt;everybody&lt;/em&gt; should be involved in overseeing incoming RFCs.&lt;/p&gt;
&lt;h2&gt;Governance WG and a new process&lt;/h2&gt;
&lt;p&gt;Generally, I think we all know that the RFC process needs to
change. It has a bunch of problems that have lead to people physically
and mentally burning out while contributing to Rust. And, as
XAMPPRocky mentioned in her post, sustainability is important for Rust
to remain a healthy project, 5, 10 or 15 years down the line.&lt;/p&gt;
&lt;p&gt;I haven't followed a lot of progress from the governance workinggroup,
but reading their charter and some of the proposed &lt;a href="http://smallcultfollowing.com/babysteps/blog/2018/06/20/proposal-for-a-staged-rfc-process/"&gt;RFC stages&lt;/a&gt;
might address some of the issues in the process. I feel that
introducing a new RFC governance body (a set of people who rotate) as
well as the concept of RFC shepherds would be beneficial to the Rust
project as a whole, and anyone who's involved in any RFC related
discussions in the future.&lt;/p&gt;
&lt;p&gt;There's some tooling issues to address as well, but I feel those are
second to the social ones.&lt;/p&gt;
&lt;h2&gt;Distributing Rust code&lt;/h2&gt;
&lt;p&gt;Wow, yea this was supposed to be a post about Rust 2020 and my
personal roadmap. While I would love to be involved co-authoring an
RFC on changing the RFC process in the ways that I propose in this
post, there's some personal projects I want to get going as well.&lt;/p&gt;
&lt;p&gt;At the beginning of the year I told myself that my SQL migration crate
&lt;code&gt;barrel&lt;/code&gt; would see a 1.0 release by the end of the year. This is
looking less and less likely, but I want to at least get close to
it. And then, next year, there will be a 1.0. There's a bunch of
improvements to the crate itself, as well as compatibility with other
crates (such as diesel and other migration toolkits), I want to make.&lt;/p&gt;
&lt;p&gt;There's &lt;code&gt;clap&lt;/code&gt; 3.0 things that are happening although maybe those will
all be done by the end of the year. Who knows?&lt;/p&gt;
&lt;p&gt;But mostly, I want to address a pain point in application
packaging. Over the last year I've been tricked into maintaining a
Linux distribution, NixOS. And while I'm not &lt;em&gt;that&lt;/em&gt; involved in the
development of it, there's some things that often come up with
packaging Rust applications that could and should be better.&lt;/p&gt;
&lt;p&gt;Mostly this is about applications, written in Rust, that want to
distribute artifacts other than their binaries as well. Be that
generated man pages, default configuration, or static files for a
website. Currently this process is entirely up to the packager of an
application and relies heavily on the application in question having
good documentation. This is also a problem for &lt;em&gt;all&lt;/em&gt; Linux
distributions, not just NixOS.&lt;/p&gt;
&lt;p&gt;Enter &lt;code&gt;cargo-dist&lt;/code&gt;, a tool that can be used by a project to easily
declare exportable artifacts and provides a way to tell an external
packaging tool (such as nix, or dpkg) where to copy files to make
a complete, working application. It &lt;del&gt;steals&lt;/del&gt; borrows some
concepts from autotools, using a &lt;code&gt;PREFIX&lt;/code&gt; and several paths that
artifacts can be copied into. This way a Rust application can easily
be made into a package by calling &lt;code&gt;cargo dist&lt;/code&gt;, which internally does
a release build, and exports required artifacts to the appropriate
places.&lt;/p&gt;
&lt;p&gt;All of this is pretty WIP and local on my laptop right now. But I
would love to finish it soon, and see projects in 2020 adopt this as a
standard to distribute files for Rust packaging.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Mon, 04 Nov 2019 10:00:00 +0100</pubDate><guid>tag:None,2019-11-04:/blog/rust-2020-the-rfc-process-and-distributions</guid><category>Blog</category><category>/dev/diary</category><category>rust</category><category>roadmap</category></item><item><title>Labels are language</title><link>/blog/labels-are-language</link><description>&lt;p&gt;A phrase that I've heard way too fucking often recently (this edition
will contain swearing and might not be suitable for children of ages
below &lt;code&gt;NaN&lt;/code&gt;) is "I don't care about labels, I want to do politics!"&lt;/p&gt;
&lt;p&gt;As one might expect, this sentiment often comes from centrists. But
more often than not, it comes from fellow leftists. People who are
otherwise somewhat radical in their approach of the world, people who
think capitalism's gotta go and (sometimes) that states and borders
are bad. And it's a stance that has confused me, and keeps confusing
me and which is why I'm now writing a blog post about it because
apparently that's what I do.&lt;/p&gt;
&lt;p&gt;The problem I have with "I don't care about labels" is that it's
analogous to "I don't care about language".&lt;/p&gt;
&lt;p&gt;Labels are a linguistic tool to talk about &lt;code&gt;$stuff&lt;/code&gt; without having to
build up an entire language from first principles in every
sentence. Labels are very useful for general conversation about
things, like "what is a table?", "what is a train?", "what is art?",
etc.&lt;/p&gt;
&lt;p&gt;When we look at the definition of labels, there's usually three
kinds. There's labels for &lt;strong&gt;natural things, with natural
definitions&lt;/strong&gt;, such as the definition of a prime number. These are
farely rare. Neither the definition of prime numbers, nor prime
numbers themselves are going to change due to cultural context.&lt;/p&gt;
&lt;p&gt;Secondly, you have labels that refer to &lt;strong&gt;natural things, with
cultural definitions&lt;/strong&gt;. These are things like planets, mountains or
rain. Definitions can change and they're also subject to cultural
differences. What you and I consider "rain" will most likely depend on
where we grew up, if there was frequent rain at all, etc.&lt;/p&gt;
&lt;p&gt;The last category are &lt;strong&gt;cultural things, with cultural definitions&lt;/strong&gt;,
such as art, sub-categories of it (movies, games, etc), as well as any
identity label. Calling myself an anarchist doesn't naturally depend
on anarchy as a concept occuring in nature, nor can I define it just
by pointing at other properties of natural definitions. Rather, I need
to pre-define a whole bunch of cultural context, for you to be able to
understand why I am an anarchist and what that means.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And that's the fucking job of labels!&lt;/strong&gt; We can't have the same 5
conversations over and over again and we can't rely on the trust that
people around us are always gonna be on our side. We should have
conversations from time to time about what these labels mean to us,
especially when it becomes clear that there's miscommunication. &lt;/p&gt;
&lt;p&gt;But also, just because we're having a conversation about labels,
doesn't mean we need to start bikeshedding their definitions and scope
(whether it be anarchy, libertarian socialist, libertarian
communists - these are all kind of similar enough to work with). Their
context is still there to be used.&lt;/p&gt;
&lt;p&gt;That doesn't mean that I am okay with any vaguely leftist label. I
have, over the last year or so, become more sceptical of communism,
talking about how you want to guillotine people and similar. Being an
anarchist means being opposed to state violence, no matter who's state
it is. But this isn't a conversation that is easy to have if I don't
already know a bunch of labels and can refer back to them. Furthermore,
maybe I don't &lt;em&gt;want&lt;/em&gt; to have this conversation in certain situations
so why would I have to engage with tankies when I don't want to?&lt;/p&gt;
&lt;p&gt;Most of the time the people who say "I don't care about labels, I
wanna do poltics", never do any politics due to lack of a platform or
language to engage with similarly minded people about strategy.
That's because political action depends on the people doing it having
some understanding of the work they're doing, how it relates to others
and themselves. There's a reason why minority groups rely on labels
(such as people in the LGBTQ community), and they serve an important
role in our discourse.&lt;/p&gt;
&lt;p&gt;This is not to say that we should try to make the onboarding easier
and use less jargon language when dealing with outsiders. Making
people more sympathetic to the radical left is important, albeit not a
job everybody might want to do.&lt;/p&gt;
&lt;p&gt;Still...I feel labels are important, especially when we deal with
internal discourse. For the sake of the conversation, and everybody
involved in it.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Fri, 20 Sep 2019 15:38:00 +0200</pubDate><guid>tag:None,2019-09-20:/blog/labels-are-language</guid><category>Blog</category><category>politics</category></item><item><title>ociTools in NixOS</title><link>/blog/ocitools-in-nixos</link><description>&lt;p&gt;With the release of NixOS 19.09 any second now, I thought I wanted to
blog about something that I've been working on, that &lt;a href="https://github.com/NixOS/nixpkgs/pull/56411"&gt;recently&lt;/a&gt;
made it into &lt;code&gt;master&lt;/code&gt;, and thus the new stable channel.&lt;/p&gt;
&lt;h2&gt;What are OCI tools?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.opencontainers.org/"&gt;Open Container Initiative&lt;/a&gt; (or OCI) produced a spec that
standardised what format containers should use. It is implemented by a
bunch of runners, such as &lt;code&gt;runc&lt;/code&gt; (the Docker/ standard Kubernetes
backend) and &lt;code&gt;railcar&lt;/code&gt; (more to that later) and outlines in exactly
what format a containers metadata and filesystem are to be stored, so
to achieve the largest possible reusability.&lt;/p&gt;
&lt;p&gt;The spec is pretty &lt;a href="https://github.com/opencontainers/runtime-spec"&gt;long&lt;/a&gt; and in some places not very
great. There's even a &lt;a href="https://blogs.oracle.com/developers/building-a-container-runtime-in-rust"&gt;blog post&lt;/a&gt; from Oracle, talking about how
implementing an OCI runner in Rust made them find bugs in the
specification.&lt;/p&gt;
&lt;h2&gt;What are ociTools?&lt;/h2&gt;
&lt;p&gt;So now the question is, what does that have to do with
NixOS/nixpkgs. The answer is simple: I wanted to be able to
containerise single applications on my server, without requiring a
container daemon (such as docker) or relying on externally built
"Docker containers" from a registry.&lt;/p&gt;
&lt;p&gt;So, &lt;code&gt;ociTools.buildContainer&lt;/code&gt; was recently merged into &lt;code&gt;nixpkgs/master&lt;/code&gt;, allowing you to do exactly that. It's usage is farely
straight forward&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; pkgs&lt;span class="p"&gt;;&lt;/span&gt; ociTools&lt;span class="o"&gt;.&lt;/span&gt;buildContainer &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;writeShellScript &lt;span class="s2"&gt;&amp;quot;run.sh&amp;quot;&lt;/span&gt; &lt;span class="s s-Multiline"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;hello&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/hello -g &amp;quot;Hello from OCI container!&amp;quot;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;    &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;outPath
  &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;args&lt;/code&gt; parameter refers to a list of paths and arguments that are
handed to a container runner to run as init. In this case it's
creating a shell script with some commands in it, then getting the
output derivation path. Alternatively, if you only want to run a
single application, you can pass it &lt;code&gt;&amp;lt;package&amp;gt;.outPath&lt;/code&gt; directly
instead.&lt;/p&gt;
&lt;p&gt;There's other options available, such as the &lt;code&gt;os&lt;/code&gt;, &lt;code&gt;arch&lt;/code&gt; and
&lt;code&gt;readonly&lt;/code&gt; flags (which aren't very interesting and have sane
defaults). Additionally to that there's &lt;code&gt;mounts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Simply specify any bind-mount you wish to setup at container init in a
similar way you would describe your filesystem with &lt;code&gt;nix&lt;/code&gt; already:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; pkgs&lt;span class="p"&gt;;&lt;/span&gt; ociTools&lt;span class="o"&gt;.&lt;/span&gt;buildContainer &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;writeShellScript &lt;span class="s2"&gt;&amp;quot;run.sh&amp;quot;&lt;/span&gt; &lt;span class="s s-Multiline"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;hello&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/hello -g &amp;quot;Hello from OCI container!&amp;quot;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;    &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;outPath
  &lt;span class="p"&gt;];&lt;/span&gt;
  mounts&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/data&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/var/lib/mydata&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Railcar + ociTools&lt;/h2&gt;
&lt;p&gt;So that's all nice and good. But what about actually running these
containers. Well, as I previously said I didn't want to have a
dependency on a management daemon such as &lt;code&gt;docker&lt;/code&gt;. Instead, I also
added a module for the afromentioned &lt;code&gt;railcar&lt;/code&gt; container runner
(Oracle please merge my PR, thank you).&lt;/p&gt;
&lt;p&gt;It wraps very cleanly around &lt;code&gt;ociTools&lt;/code&gt; and generates &lt;code&gt;systemd&lt;/code&gt; units
to start containers, restarting them if they crash. This way you can
express applications purely in &lt;code&gt;nix&lt;/code&gt;, give them access to only the
things they need, and be sure that their configuration is in line with
the rest of your system rebuild.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;services&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;railcar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;containers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s s-Multiline"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;hello&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/hello -g &amp;quot;Hello railcar!&amp;quot;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The metadata interface for &lt;code&gt;mounts&lt;/code&gt;, etc is the same for &lt;code&gt;railcar&lt;/code&gt; as
for &lt;code&gt;ociTools&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Anyway, I hope you enjoy. There is definitely things to improve,
especially considering the vastness of the OCI spec. Plus, at the
moment &lt;code&gt;ociTools&lt;/code&gt; does require a bunch of manual setup work for an
application to function, if it, say, runs a webserver. It would be
cool if some NixOS modules could be re-used to make this configuration
easier. But I'm sure someone else is gonna have fun figuring that out.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Mon, 09 Sep 2019 18:00:00 +0200</pubDate><guid>tag:None,2019-09-09:/blog/ocitools-in-nixos</guid><category>Blog</category><category>/dev/diary</category><category>NixOS</category><category>Virtualisation</category></item><item><title>Starting a public inbox</title><link>/blog/starting-a-public-inbox</link><description>&lt;p&gt;I've been a lot more active on this blog in the last year than I have
previously, and that makes me pretty happy. I'm trying to become less
obsessed about publishing only perfect diamonds made of words, but
instead also publishing articles that might still have some flaws or
that I haven't rewritten twelve times yet ;)&lt;/p&gt;
&lt;p&gt;As a result of this I have actually gotten more and more e-mails by
people saying that they read my blog, giving me feedback and sometimes
submitting patches to my &lt;a href="https://sr.ht/~spacekookie/website"&gt;website&lt;/a&gt; repository to fix typos or bad
formatting. And that's pretty cool.&lt;/p&gt;
&lt;p&gt;Recently I started thinking if the format of e-mail might not be well
suited for comments as well. Not just to me, but to allow other
readers to talk &lt;em&gt;about&lt;/em&gt; the stuff I post. I wasn't super sure if this
was such a great idea, after all...this is the internet we're talking
about. Someone will be an asshole and ruin it for everybody.&lt;/p&gt;
&lt;p&gt;Then I discovered Drew DeVaults &lt;code&gt;public-inbox&lt;/code&gt; mailing list,
which is basically exactly what I thought about creating,
hosted on source hut.&lt;/p&gt;
&lt;p&gt;It might still be a terrible idea, but it's one I wanna try. I also
wanna automatically post new blog posts &lt;em&gt;to&lt;/em&gt; the mailing list, as
plain text, so people don't have to fuss around with my RSS feed if
they don't want to. I will host my &lt;code&gt;public-inbox&lt;/code&gt; on source hut for
now too, especially considering that I've been trying it out for a lot
of smaller personal stuff, it makes sense. And I really quite like it
(might write about that in the future too)&lt;/p&gt;
&lt;p&gt;So, if you have comments, questions or want to fix typos,
feel free to check out my &lt;a href="https://lists.sr.ht/~spacekookie/public-inbox"&gt;public-inbox&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let's see how this goes then 😀&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Sat, 20 Jul 2019 00:00:00 +0200</pubDate><guid>tag:None,2019-07-20:/blog/starting-a-public-inbox</guid><category>Blog</category><category>blogging</category><category>communication</category></item><item><title>Bikeshedding disk partitioning</title><link>/blog/bikeshedding-disk-partitioning</link><description>&lt;p&gt;I recently got a new Thinkpad. Well...new is a stretch.
It's an X230, featuring an i5 and 16GB of RAM.&lt;/p&gt;
&lt;p&gt;One of the first things I did with this laptop was to &lt;a href="https://octodon.social/@spacekookie/102150706024564666"&gt;flash coreboot on it&lt;/a&gt;.
This is something I've always wanted to be able to do,
but so far lacked hardware that was supported.
And generally, it felt like finally maybe I could have a laptop to tinker around with.&lt;/p&gt;
&lt;p&gt;And that's where this post begins...&lt;/p&gt;
&lt;h2&gt;Encrypted disk&lt;/h2&gt;
&lt;p&gt;So from the start I knew I wanted to have a fully encrypted disk.&lt;/p&gt;
&lt;p&gt;What that means is that your &lt;code&gt;/boot&lt;/code&gt; partition 
(whether it is it's own partition or not), is also encrypted.&lt;/p&gt;
&lt;p&gt;Secondly, I don't like (U)EFI...
What that means is that I'm installing GRUB
in the MBR (with a DOS partition table) instead.&lt;/p&gt;
&lt;p&gt;Now: GRUB stage 1 can handle the encryption for us,
but there's some limitations&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keyboard layout limited to &lt;code&gt;US&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/boot&lt;/code&gt; can only be certain partition type&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/&lt;/code&gt; and &lt;code&gt;/boot&lt;/code&gt; need be contained in an LVM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last one &lt;em&gt;might&lt;/em&gt; not be accurate if you only want
to have an &lt;code&gt;ext4&lt;/code&gt; (or similar) rootfs. But because I
want to have a &lt;code&gt;zfs&lt;/code&gt; root, I need to embed it into an LVM.
This is also the reason why &lt;code&gt;/boot&lt;/code&gt; needs to be it's own partition.
After we've done all this, we will install a linux distribution of choice
(which we'll reveal later).&lt;/p&gt;
&lt;p&gt;Anyway, let's get started!&lt;/p&gt;
&lt;h2&gt;Preparing the disk&lt;/h2&gt;
&lt;p&gt;(Feel free to skip this step)&lt;/p&gt;
&lt;p&gt;Something you might want to do is letting your disk look
otherwise uninitialised, or "securely erasing" any data
that is already on it.
But generating random data is a lot of work and &lt;code&gt;/dev/urandom&lt;/code&gt;
is very slow.&lt;/p&gt;
&lt;p&gt;Instead you can create a crypto-disk (luks) on it, then fill it
with zero's. But because of the encryption it will seem random.&lt;/p&gt;
&lt;p&gt;(&lt;code&gt;/dev/sda&lt;/code&gt; is my disk in this example because lolwat is nvme even?)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cryptsetup&lt;span class="w"&gt; &lt;/span&gt;luksFormat&lt;span class="w"&gt; &lt;/span&gt;/dev/sda1
&lt;span class="gp"&gt;$ &lt;/span&gt;cryptsetup&lt;span class="w"&gt; &lt;/span&gt;luksOpen&lt;span class="w"&gt; &lt;/span&gt;/dev/sda&lt;span class="w"&gt; &lt;/span&gt;sda_crypto
&lt;span class="gp"&gt;$ &lt;/span&gt;dd&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/zero&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/mapper/sda_crypto&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;512&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;progress
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This might take a while, but considerably less time than filling
the disk with random data. After this is done, you might want to
actually wipe the first bunch of bytes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cryptsetup&lt;span class="w"&gt; &lt;/span&gt;luksClose&lt;span class="w"&gt; &lt;/span&gt;sda_crypto
&lt;span class="gp"&gt;$ &lt;/span&gt;dd&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/urandom&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/sda&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1M&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Basic partitioning&lt;/h2&gt;
&lt;p&gt;So what we want to do is setup a single partition on &lt;code&gt;/dev/sda&lt;/code&gt;,
the same way we did to prepare the disk. Then repeat the previous
command to setup a cryptodisk.&lt;/p&gt;
&lt;p&gt;What follows is the LVM setup:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;pvcreate&lt;span class="w"&gt; &lt;/span&gt;lvm
&lt;span class="gp"&gt;$ &lt;/span&gt;vgcreate&lt;span class="w"&gt; &lt;/span&gt;vg0&lt;span class="w"&gt; &lt;/span&gt;/dev/mapper/lvm
&lt;span class="gp"&gt;$ &lt;/span&gt;lvcreate&lt;span class="w"&gt; &lt;/span&gt;vg0-boot&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;1G
&lt;span class="gp"&gt;$ &lt;/span&gt;lvcreate&lt;span class="w"&gt; &lt;/span&gt;vg0-swap&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;16G
&lt;span class="gp"&gt;$ &lt;/span&gt;lvcreate&lt;span class="w"&gt; &lt;/span&gt;vg0-root&lt;span class="w"&gt; &lt;/span&gt;-L&lt;span class="w"&gt; &lt;/span&gt;+100%FREE&lt;span class="w"&gt; &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I included the &lt;code&gt;swap&lt;/code&gt; partition in the LVM instead of as a ZFS subvolume
because those can sometimes deadlock and this just makes things easier.&lt;/p&gt;
&lt;p&gt;Now we want to create the filesystems. 
For &lt;code&gt;/boot&lt;/code&gt; we can just use &lt;code&gt;mkfs.ext4&lt;/code&gt;,
but consider that I want to use &lt;code&gt;zfs&lt;/code&gt; on &lt;code&gt;/&lt;/code&gt;,
that will require some more work.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;zpool&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;rtank&lt;span class="w"&gt; &lt;/span&gt;/dev/mapper/vg0-root
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Feel free to call your pool whatever!
At this point you could also create subvolumes to 
split &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/home&lt;/code&gt;, ... if you wanted.&lt;/p&gt;
&lt;h2&gt;Mounting &amp;amp; Configuration&lt;/h2&gt;
&lt;p&gt;So that's all good. How do we initialise this system now?
We need to mount the zfs pool first, then &lt;code&gt;/boot&lt;/code&gt; and then install
our linux secret distribution of choice (spoilers: it's &lt;a href="https://nixos.org"&gt;NixOS&lt;/a&gt;!)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mnt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;boot&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;zpool&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;rtank&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;mount&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;zfs&lt;/span&gt; &lt;span class="n"&gt;rtank&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mnt&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;mount&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vg0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;boot&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mnt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;boot&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;nixos&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mnt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That last line is obviously NixOS specific.
You now have a fully encrypted disk setup, without
using EFI. Wuuh!&lt;/p&gt;
&lt;p&gt;The rest of this post I want to talk about how to make this
all work with NixOS and reproducable configuration.&lt;/p&gt;
&lt;p&gt;Most of what we need to configure is in the &lt;code&gt;boot&lt;/code&gt; option.
Let's go through the settings one by one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;boot.loader.grub&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;efiSupport = false&lt;/code&gt; actually the default but I like being explicit&lt;/li&gt;
&lt;li&gt;&lt;code&gt;copyKernels = true&lt;/code&gt; enable this to avoid problems with ZFS becoming unbootable&lt;/li&gt;
&lt;li&gt;&lt;code&gt;device = "/dev/sda"&lt;/code&gt; replace this with the device that holds your GRUB&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zfsSupport = true&lt;/code&gt; to enable ZFS support 😅&lt;/li&gt;
&lt;li&gt;&lt;code&gt;enableCryptodisk = true&lt;/code&gt; to enable stage-1 encryption support&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;boot.zfs.devNodes = "/dev"&lt;/code&gt; to point ZFS at the correct device tree (not 100% if required)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fileSystems."/".encrypted&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;enable = true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;label = "lvm"&lt;/code&gt; the label of your LVM&lt;/li&gt;
&lt;li&gt;&lt;code&gt;blkDev = "/dev/disk/by-uuid/f1440abd-99e3-46a8-aa36-7824972fee54"&lt;/code&gt; the disk that
  ZFS is installed to. You can find this out by looking at your symlinks in 
  &lt;code&gt;/dev/disk/by-uuid&lt;/code&gt; and picking the correct one.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;networking.hostId&lt;/code&gt; needs to be set to some random 8 bytes    &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Following is the complete config to make it easier to copy stuff from:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;efiSupport&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;copyKernels&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dev/sda&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;zfsSupport&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;enableCryptodisk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zfs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;devNodes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dev&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;fileSystems&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;lvm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;blkDev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dev/disk/by-uuid/f1440abd-99e3-46a8-aa36-7824972fee54&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;networking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hostId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;random shit&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And that's it.
If you spot any errors in this article (or any for that matter),
feel free to e-mail me or send me a PR over on github.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Thu, 11 Jul 2019 00:00:00 +0200</pubDate><guid>tag:None,2019-07-11:/blog/bikeshedding-disk-partitioning</guid><category>Blog</category><category>linux</category><category>zfs</category><category>nixos</category></item><item><title>Usable GPG with WKD</title><link>/blog/usable-gpg-with-wkd</link><description>&lt;p&gt;With the recent &lt;a href="https://gist.github.com/rjhansen/67ab921ffb4084c865b3618d6955275f"&gt;SKS keyserver vulnerability&lt;/a&gt;,
people have been &lt;strike&gt;arguing&lt;/strike&gt; reasonably talking on the GnuPG mailing list
about how to proceed with keyservers, public key exchanges
and the GPG ecosystem as a whole.&lt;/p&gt;
&lt;p&gt;As part of this &lt;a href="https://wiki.gnupg.org/WKD"&gt;WKD&lt;/a&gt; was mentioned.
It stands for "Web Key Directory" and is a standard 
for making a users public key available via their e-mail provider
or server with the domain that corresponds to their e-mail address.
There's several clients (such as &lt;a href="https://www.enigmail.net/index.php/en/"&gt;Enigmail&lt;/a&gt; in Thunderbird)
that will use this standard to automatically fetch a user's public key,
when writing an e-mail to them.&lt;/p&gt;
&lt;p&gt;As an example: my e-mails are hosted with &lt;a href="https://mailbox.org"&gt;mailbox.org&lt;/a&gt;,
but I use my own website as an e-mail alias.
This means that I can make my public key available via my website,
and clients using WKS could then get it automatically.&lt;/p&gt;
&lt;p&gt;If you don't have your own domain and use a webhoster instead,
you might still be able to use this.
There's a &lt;a href="https://wiki.gnupg.org/WKD#Mail_Service_Providers_offering_WKD"&gt;list of supported hosters&lt;/a&gt; that you should check out.&lt;/p&gt;
&lt;h2&gt;Setting this up&lt;/h2&gt;
&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; in newer versions of &lt;code&gt;gpg&lt;/code&gt; the tool &lt;code&gt;gpg-wks-client&lt;/code&gt; is included,
which can handle setting up the folder structure for you automatically).&lt;/p&gt;
&lt;p&gt;There's two ways of making your public keys accessable this way:
the advanced and the direct way.
This post will only talk about the latter, because I find it easier.&lt;/p&gt;
&lt;p&gt;You need to create a &lt;code&gt;.well-known/openpgpkey&lt;/code&gt; directory on your server.
In this directory, place a &lt;code&gt;policy&lt;/code&gt; file.
This can be zero-length, but is used to check for WKD capability.
Next, create a &lt;code&gt;hu&lt;/code&gt; folder inside it
(&lt;strike&gt;no idea what this stands for...&lt;/strike&gt;
— as pointed out by an attentive reader, it stands for &lt;a href="https://www.gnupg.org/blog/20160830-web-key-service.html"&gt;hashed-userid&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Next, take the prefix of your e-mail address
(i.e. in &lt;code&gt;kookie@spacekookie.de&lt;/code&gt;, this would be &lt;code&gt;kookie&lt;/code&gt;),
hash it with SHA-1 and then encode the output with z-base-32.
You can use &lt;a href="https://cryptii.com/pipes/z-base-32"&gt;this&lt;/a&gt; convenient encoding website.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; Also pointed out by a reader, you can actually use 
&lt;code&gt;gpg --with-wkd -l &amp;lt;email&amp;gt;&lt;/code&gt; to display your hashed User ID
instead of using an external resource for this.&lt;/p&gt;
&lt;p&gt;Export the &lt;strong&gt;binary&lt;/strong&gt; version of your pubkey (so without &lt;code&gt;-a&lt;/code&gt;)
and place it in the &lt;code&gt;hu&lt;/code&gt; folder, under the name that you just computed.&lt;/p&gt;
&lt;p&gt;The resulting folder structure should look something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;tree&lt;span class="w"&gt; &lt;/span&gt;.well-known/&lt;span class="w"&gt; &lt;/span&gt;
.well-known/
└──&lt;span class="w"&gt; &lt;/span&gt;openpgpkey
&lt;span class="w"&gt;    &lt;/span&gt;├──&lt;span class="w"&gt; &lt;/span&gt;hu
&lt;span class="w"&gt;    &lt;/span&gt;│&lt;span class="w"&gt;   &lt;/span&gt;└──&lt;span class="w"&gt; &lt;/span&gt;nzn5f4t6k15893omwk19pgzfztowwkhs
&lt;span class="w"&gt;    &lt;/span&gt;└──&lt;span class="w"&gt; &lt;/span&gt;policy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You need to make sure that this folder is accessable through your webserver
(this either involves including it in a static site or configuring nginx correctly).
But fundamentally, that's it!&lt;/p&gt;
&lt;p&gt;You can test if it works by setting a new &lt;code&gt;GNUPGHOME&lt;/code&gt; and running this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;env&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;GNUPGHOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;gpg&lt;span class="w"&gt; &lt;/span&gt;--locate-keys&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;your-email-here&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And that's it! Clients like Enigmail, KMail or GpgOL for Outlook
will now automatically fetch your public key for any message they send.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Tue, 02 Jul 2019 00:00:00 +0200</pubDate><guid>tag:None,2019-07-02:/blog/usable-gpg-with-wkd</guid><category>Blog</category><category>gpg</category><category>security</category><category>usability</category></item><item><title>Allocations are good, actually</title><link>/blog/allocations-are-good-actually</link><description>&lt;p&gt;Something that you can often hear in the Rust community,
especially from people who were previously C or C++ developers,
is the adage "allocations are slow".&lt;/p&gt;
&lt;p&gt;The other day a friend asked me how to create a consecutive list of numbers.
I pointed her at &lt;code&gt;(0..).take(x).collect()&lt;/code&gt; which can be made into a &lt;code&gt;Vec&amp;lt;_&amp;gt;&lt;/code&gt;,
with a number of her choice.
It did made me think however about how this could be done
much nicer in a allocation-free manner.&lt;/p&gt;
&lt;p&gt;It lead me to come up with the following code which creates a &lt;code&gt;[_; _]&lt;/code&gt; slice,
depending on which integer representation and length you choose.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fold&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So with this in mind, I wanted to run some comparisons.
I chose the numbers so that 32768 consecutive numbers would be generated.
I compiled the example with both &lt;code&gt;Debug&lt;/code&gt; and &lt;code&gt;Release&lt;/code&gt; mode.
(All of these measurements are done with &lt;code&gt;rustc 1.33.0 (2aa4c46cf 2019-02-28)&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;Let's start with the non-allocating version.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;target/debug/playground
&lt;span class="go"&gt;target/debug/playground  1.45s user 0.00s system 99% cpu 1.457 total&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;target/release/playground
&lt;span class="go"&gt;target/release/playground  0.27s user 0.00s system 99% cpu 0.270 total&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cool! So as you can see, the &lt;code&gt;Release&lt;/code&gt; profile is over 500% faster.
And performance-wise this is quite reasonable.&lt;/p&gt;
&lt;p&gt;Let's see how an allocating implementation stacks up to it.
The code used here is the following.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;u32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So how fast is this gonna be?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;target/debug/playground
&lt;span class="go"&gt;target/debug/playground  0.01s user 0.00s system 93% cpu 0.010 total&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;target/release/playground
&lt;span class="go"&gt;target/release/playground  0.00s user 0.00s system 85% cpu 0.005 total&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What? ...it's faster?!&lt;/p&gt;
&lt;p&gt;Well, I guess this does to show that it's not as simple as saying "allocations are bad".
Avoiding allocations at all cost can slow you down.&lt;/p&gt;
&lt;p&gt;Thanks for coming to my TED talk!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;. . .&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Yes but &lt;em&gt;why&lt;/em&gt;?&lt;/h2&gt;
&lt;p&gt;Okay maybe you're more curious than that and want to understand what's going on here.
So come along, let's read some assembly!&lt;/p&gt;
&lt;p&gt;Let's focus mostly on the release profile here,
because &lt;code&gt;Debug&lt;/code&gt; generates a lot of code that makes it harder to understand.
So we have two code snippets that we should throw into &lt;a href="https://rust.godbolt.org/"&gt;godbolt&lt;/a&gt; to see what rustc does.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// This doesn&amp;#39;t allocate&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fold&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// This does&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;u32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's have a look at the assembly that the &lt;code&gt;vec()&lt;/code&gt; function generates.&lt;/p&gt;
&lt;p&gt;&lt;skip&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;.LCPI0_0:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="na"&gt;.long&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="na"&gt;.long&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="na"&gt;.long&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="na"&gt;.long&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;

&lt;span class="c1"&gt;# ... snip ...&lt;/span&gt;

&lt;span class="nl"&gt;example:&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nl"&gt;vec:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;rbx&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="no"&gt;rbx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;rdi&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="no"&gt;edi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;131072&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="no"&gt;esi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;qword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;rip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;__rust_alloc@GOTPCREL&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;rax&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;je&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;.LBB0_4&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;movdqa&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;xmm0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;xmmword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;rip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;.LCPI0_0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="no"&gt;ecx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;movdqa&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;xmm8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;xmmword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;rip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;.LCPI0_1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;movdqa&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;xmm9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;xmmword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;rip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;.LCPI0_2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;movdqa&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;xmm10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;xmmword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;rip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;.LCPI0_3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;movdqa&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;xmm4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;xmmword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;rip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;.LCPI0_4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;movdqa&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;xmm5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;xmmword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;rip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;.LCPI0_5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;movdqa&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;xmm6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;xmmword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;rip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;.LCPI0_6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;movdqa&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;xmm7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;xmmword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;rip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;.LCPI0_7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;movdqa&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;xmm1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;xmmword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;rip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;.LCPI0_8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nl"&gt;.LBB0_2:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;movdqa&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;xmm2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;xmm0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;paddd&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="no"&gt;xmm2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;xmm8&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# ... snip ...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;
&lt;span class="nl"&gt;.LBB0_4:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="no"&gt;edi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;131072&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="no"&gt;esi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;qword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;rip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;_ZN5alloc5alloc18...@GOTPCREL&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ud2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(full code dump &lt;a href="https://pastebin.com/zDXi7qtt"&gt;here&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;/skip&gt;&lt;/p&gt;
&lt;p&gt;As you can see this uses the "Move Aligned Packed Integer Values" instructions in x86_64.
From some &lt;code&gt;x86&lt;/code&gt; docs:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Moves 128, 256 or 512 bits of packed doubleword/quadword integer values from the source operand (the second operand) to the destination operand (the first operand).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Basically the LLVM can figure out that our numbers are predictable
and can allocate them in a way that is batchable.&lt;/p&gt;
&lt;p&gt;We will already see how the non-alloc code is going to be slower:
because the code that assigns numbers is less unterstandable to a compiler
(i.e. assigning values to an array sequencially) this will not end up being batched.&lt;/p&gt;
&lt;p&gt;That's not to say that alloc code is going to be this fast on every platform
(RISC instruction sets lack many vectoring techniques)
and this doesn't even take embedded targets into account.&lt;/p&gt;
&lt;p&gt;But there you have it.&lt;/p&gt;
&lt;p&gt;LLVM is magic...&lt;/p&gt;
&lt;p&gt;... and saying "allocations are bad" really isn't telling the whole story.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Sun, 07 Apr 2019 00:00:00 +0200</pubDate><guid>tag:None,2019-04-07:/blog/allocations-are-good-actually</guid><category>Blog</category><category>Rust</category><category>programming</category></item><item><title>home-manager, or: how not to yakhave</title><link>/blog/home-manager-or-how-not-to-yakhave</link><description>&lt;p&gt;Don't expect the bait-and-switch titles to remain forever.
I just thought it was fitting for this one too 😉.&lt;/p&gt;
&lt;h2&gt;Some background&lt;/h2&gt;
&lt;p&gt;Ever since I started venturing into computer programming and
using more and more tools that used &lt;code&gt;dotfiles&lt;/code&gt;, I've been
frustrated at the lack of good tools when it came to synchronising
these files.&lt;/p&gt;
&lt;p&gt;And that's not for lack of options.
Either I disagree fundamentally with what I want a sync tool to do
or nobody had come at the problem from the same angle as me before.
This is not to bash on other projects or solutions.
I know many people who are very happy with
either keeping their dotfiles in a large git repo, symlinking manually,
making &lt;code&gt;~&lt;/code&gt; a git repo or using various tools that automate the symlink process.&lt;/p&gt;
&lt;p&gt;The problem I had was that not all my computers were the same.
As in, I didn't neccessarily want the same configs on all of them.
Because this is where it becomes complicated.&lt;/p&gt;
&lt;p&gt;I had been thinking about writing a tool to do the things I wanted to do before.
Thinking back to my post about failure and limiting scope, I never started it.
While making a lot of drawing board attempts, I never wrote a single line of code
because I could tell that it would lead me down a dark path.&lt;/p&gt;
&lt;p&gt;Reading about people on reddit from time to time who started their own
"ansible but for dotfiles" projects that never went anywhere,
I felt like I was doing the right thing by not even starting.&lt;/p&gt;
&lt;p&gt;So nothing happened for a while. Until recently.&lt;/p&gt;
&lt;h2&gt;Enter: nix&lt;/h2&gt;
&lt;p&gt;In case you don't know it, &lt;code&gt;nix&lt;/code&gt; is a functional programming language
and pure package-manager for unix systems.
Yes, that includes MacOS.
There is a linux distribution built around it called &lt;a href="https://nixos.org/nixos"&gt;NixOS&lt;/a&gt; which utilises
&lt;code&gt;nix&lt;/code&gt; as a package manager and configuration language heavily.&lt;/p&gt;
&lt;p&gt;So what does pure-packaging really even mean?
Have you ever had the situation where you upgraded your system
and half way through something failed and now you ended up with a broken system
because some of the packages had already changed while others had not?&lt;/p&gt;
&lt;p&gt;Yea, that's what people would call "impure packaging".&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;nix&lt;/code&gt; on the other hand this cannot happen,
since packages are atomic, meaning that after something is built,
it can't be changed again. Doing an update? New package.
Changing a small config? New package.
It means that not only can failing upgrades be seemlessly be rolled back
but also that two different versions of the same library
can easily be installed at the same time.&lt;/p&gt;
&lt;p&gt;Yes, that's right: no more "DLL hell"!&lt;/p&gt;
&lt;p&gt;Well okay so why am I fangirling about &lt;code&gt;nix&lt;/code&gt; here?
Apart from the fact that I've been dabbling with NixOS quite a bit recently,
to the point where I have basically replaced all my &lt;a href="https://archlinux.org"&gt;Arch&lt;/a&gt; installs with NixOS now...&lt;/p&gt;
&lt;h2&gt;Enter: home-manager&lt;/h2&gt;
&lt;p&gt;You already saw it in the title of this post, but I wanted to re-introduce it.
What exactly is &lt;code&gt;home-manager&lt;/code&gt;? &lt;/p&gt;
&lt;p&gt;It's &lt;code&gt;nix&lt;/code&gt;, but for your userspace!
Not only does it not require root permissions,
meaning you can install packages just for you locally
(well okay, &lt;code&gt;nix&lt;/code&gt; can do this as well but...besides the point).&lt;/p&gt;
&lt;p&gt;More importantly, &lt;code&gt;home-manager&lt;/code&gt; adds modules and utilities to manage userspace configurations.
Everything is sourced from &lt;code&gt;~/.config/nixpkgs/&lt;/code&gt; (you can move that IIRC)
which is then used to generate all your configuration files.&lt;/p&gt;
&lt;p&gt;Config files are kept in the nix store (which is usually located at &lt;code&gt;/nix&lt;/code&gt;)
and then symlinked to their destination.&lt;/p&gt;
&lt;p&gt;Right. Now I can practically hear you all saying:
"but didn't you say you didn't like tools that just symlinked stuff?"&lt;/p&gt;
&lt;p&gt;Well..yes, and no. Obviously symlinking a config is much nicer than having to copy them around.
What I disliked about tools that symlink configs to places from some other place
was that I was still responsible for manage that "other place".&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;nix&lt;/code&gt;, I never touch the store directly. In fact you don't ever do that!
Instead I edit the &lt;code&gt;home.nix&lt;/code&gt; configuration (or sub-configs when it gets too complicated)
that then take some inputs, define the outputs and &lt;code&gt;nix&lt;/code&gt; makes sure that the configs
are then where they need to be.&lt;/p&gt;
&lt;p&gt;It gives me a single source of truth, but the best thing is
that it's not a dumb source of truth: nix is a programming language!
What that means is that I can dynamically adjust some config contents
according to what system I'm running on, while not having to worry about
keeping it all sane.&lt;/p&gt;
&lt;p&gt;I'm really happy I didn't write my own "ansible but for dotfiles"
and I think I'd recommend nobody do that
(I mean...unless that's your kink - I don't judge!).
But I'm even more happy of having been introduced to &lt;code&gt;nix&lt;/code&gt;
and &lt;code&gt;home-manager&lt;/code&gt; in particular.&lt;/p&gt;
&lt;p&gt;I'd much rather help write some re-usable modules,
that other people can also take advantage of,
than reinventing the wheel from scratch. Again.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Thu, 21 Mar 2019 00:00:00 +0100</pubDate><guid>tag:None,2019-03-21:/blog/home-manager-or-how-not-to-yakhave</guid><category>Blog</category><category>/dev/diary</category><category>reflections</category><category>programming</category><category>nix</category></item><item><title>Rust 2019: how we make decisions</title><link>/blog/rust-2019-how-we-make-decisions</link><description>&lt;p&gt;I'm late to the party, I know.
But writing this post took a little longer.
In fact, I wrote it three times, not really sure where I wanted it to go and what I wanted to say.
In the end, I think most things have already been said.
So this will be short.&lt;/p&gt;
&lt;h2&gt;Problems&lt;/h2&gt;
&lt;p&gt;There have been a great number of blog posts about the problems that the Rust community is facing.
I recommend you read some of them because they're really good.
For example &lt;a href="https://boats.gitlab.io/blog/post/rust-2019/"&gt;boats&lt;/a&gt; who published an article early december about "Organisational Dept".
Or &lt;a href="https://deterministic.space/rust-2019.html"&gt;killercup&lt;/a&gt; about how we count contributions (and other things).
Or &lt;a href="https://yakshav.es/rust-2019/"&gt;skade&lt;/a&gt;, who published a small collection of articles on organisational subjects.&lt;/p&gt;
&lt;p&gt;There's many more under the &lt;a href="https://twitter.com/search?q=%23rust2019&amp;amp;src=typed_query"&gt;#rust2019&lt;/a&gt; hashtag on twitter.&lt;/p&gt;
&lt;p&gt;My point is: you can read about what the issues are elsewhere, from more perspectives.
There's no point in me trying to rehash the same stuff again.
I'm not that good a writer that I will bring anything to the table that these people haven't already.&lt;/p&gt;
&lt;p&gt;In my opinion the issues we have at the moment are because of two things.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Teams that have too much responsibility&lt;/li&gt;
&lt;li&gt;Bad tools&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(I won't really talk about the tools issue in this post.
In summary: the tools we use to communicate are all garbage.
And github and discourse comments are terrible for debates.
Really, any linear chat platform is terrible
- there might be another article at some point)&lt;/p&gt;
&lt;p&gt;As I've said, there are plenty of articles that go 
into &lt;em&gt;what&lt;/em&gt; is the problem with our current process.
I want to focus on the &lt;em&gt;why&lt;/em&gt;, &lt;em&gt;how&lt;/em&gt; and &lt;em&gt;how we stop it&lt;/em&gt; bit of that.&lt;/p&gt;
&lt;p&gt;And first we need to talk about how things are built.&lt;/p&gt;
&lt;h2&gt;Vision vs Implementation&lt;/h2&gt;
&lt;p&gt;Fundamentally there are two parts to design:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vision&lt;/strong&gt; is what drives a project forward, 
creating new concepts and thinking about their implications,
while &lt;strong&gt;Implementation&lt;/strong&gt; is finding the most elegant, 
sustainable and performant way of making vision a reality!&lt;/p&gt;
&lt;p&gt;Now, these two can very often not be separated as easily as I make it out there.
Take the example of the CLI-WG.
When we first assembled earlier this year, we started working on a vision:
"how should CLI development look".
What followed then was an implementation of the vision, 
as closely as we could manage with the resources and time available.
I would argue that during the implementation period of the vision,
some aspects of &lt;em&gt;what&lt;/em&gt; we thought should be done
were influenced by things we learned about &lt;em&gt;how&lt;/em&gt; to do them.
Like hitting a moving target.
To some extent this is how most software development works,
unless you are working towards a &lt;em&gt;very&lt;/em&gt; well defined spec!&lt;/p&gt;
&lt;p&gt;Having the same group of people be in charge of both the overall 
vision for a system and it's implementation isn't a bad thing,
&lt;em&gt;given that the system is small enough!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And this is where teams come in!
Splitting up the community into smaller groups who work on the same stuff,
so that this kind of collaboration becomes possible again.&lt;/p&gt;
&lt;p&gt;In a way, the Rust 2018 working groups were inspired by the same idea.
The difference between teams and working groups being,
that the latter has a more loosely defined governance structure and allows people
to join and collaborate easier and more quickly.
There's less "established structure" in a working group.
These lower barriers are one of the reasons why I'm a huge fan of working groups,
and feel like the Rust project should expand on them in the future.
Maybe some teams could even be replaced.&lt;/p&gt;
&lt;p&gt;But that's not fundamentally the issue that the project is facing.&lt;/p&gt;
&lt;h2&gt;Blurring the lines&lt;/h2&gt;
&lt;p&gt;Problems arise when these lines are blurred too much.
This happens with both discussions, as well as to teams of people,
who get involved in too many things.
Ultimately, we need to face the fact that days are short,
people's time is limited and the number of responsibilities a single person can have
isn't infinite!&lt;/p&gt;
&lt;p&gt;Througout previous blog posts and conversations with others,
the need or "desire" to have better communication channels has been made clear.
And I feel that we need to work on the way that we communicate,
if we are ever to fix the way that we make decisions.&lt;/p&gt;
&lt;p&gt;But before I go into detail about what that means to &lt;em&gt;me&lt;/em&gt;, specifically,
I want to talk quickly about the core team.&lt;/p&gt;
&lt;p&gt;The core team is a medium sized group of Rust developers,
who oversee large areas of the development of Rust.
As the website puts it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Overall direction and policies of the project,
subteam leadership, cross-cutting concerns. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As such, I feel it would be the perfect candidate to step back from implementation,
and focus on both vision for the entire language,
as well as communication among smaller teams.
Unfortunately this hasn't seemed to be the case in the past
and is something the core team should work on this year.&lt;/p&gt;
&lt;p&gt;Note that I think, that this is a responsibly that should also not be taken lightly.
Most of the members of the core team are also active in other teams,
sometimes even leading them.
I feel that this is one of the reasons why this role has been neglected.&lt;/p&gt;
&lt;h2&gt;Solutions&lt;/h2&gt;
&lt;p&gt;So I would sugest something, that I've heard others talk about before,
although rarely publicly, which might be considered a bit of a hot take.&lt;/p&gt;
&lt;p&gt;The core team should be rotated.&lt;/p&gt;
&lt;p&gt;What that means is that the core team in itself still exists,
does a certain number of jobs and should be considered quite a time-intensive commitment.
But the people involved in it shouldn't stay involved with it forever.
Even if it's currently (practically) already the case that the team rotates,
making this more explicit and making the roles of the core team a central part of
how other teams communicate and operate, I feel would benefit the overall
contribution climate of the rust project significantly.&lt;/p&gt;
&lt;p&gt;Ultimately, we have a problem in how we communicate.
The lines between &lt;em&gt;vision&lt;/em&gt; and &lt;em&gt;implementation&lt;/em&gt; get blurred too often.
Not only in RFC discussions. 
Implementation specific bikesheds on github
often result in new rationale being pushed forward,
that have nothing to do with the actual question at hand.
And as such, people often talk past each other.&lt;/p&gt;
&lt;p&gt;I don't know how wide the communication scope of the core team should be,
but I definitely think that moving it's responsibility away from implementation
and back towards communication and fostering collaboration between teams and working groups
is the approach we will have to take this year to solve our problems of
Organisational dept!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Mon, 21 Jan 2019 00:00:00 +0100</pubDate><guid>tag:None,2019-01-21:/blog/rust-2019-how-we-make-decisions</guid><category>Blog</category><category>/dev/diary</category><category>rust</category></item><item><title>Hacking is political</title><link>/blog/hacking-is-political</link><description>&lt;p&gt;I'm just coming back from the Chaos Communication Congress,
a four day event just after Christmas.
It was my fourth one in total, and now the third in a row
(the first being 25C3 as a smol girl).&lt;/p&gt;
&lt;p&gt;It's hard to describe the C3 (abreviation for the congress, opposed to the CCC, the club).
Some call it a "hacker conference" which is...in some ways accurate,
but often doesn't manage to capture what it is.
Not to mention relies on the external definition of a "hacker" to describe it.
Other's call it a "tech event" or "tech conference" which really isn't accurate either.
There are lots of artists and non-tech people represented
and I feel these experiences shouldn't be ignored.&lt;/p&gt;
&lt;p&gt;The C3 has been in Hamburg for quite a while but was forced to move last year
due to the congress centre there being remodeled (read "torn down").
After remodelling the venue would also not be suitable for the event anymore,
meaning that a semi-permanent move had to be initiated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I didn't enjoy last year's Congress.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not only was it plagued by loads of logistical problems and bad adaptation of the new space,
there were political issues around the organisation of the event and how decisions were made.
Last year's congress showed off that the CCC (the club) had a problem with apoliticality.&lt;/p&gt;
&lt;h2&gt;Apolitical Hackers&lt;/h2&gt;
&lt;p&gt;I've been rather loud about the apolitical or centrist parts of the hacker movement.
Conflation between the terms "maker" and "hacker" have further undermined the movement
with capitalist and neoliberal ideas.&lt;/p&gt;
&lt;p&gt;That isn't to say that everybody in the hacker scene
needs to be continously aware of all political implications of their actions at all times.
Danger arises from people who don't feel like political action is important &lt;em&gt;at all&lt;/em&gt;
or who represent centrist, capitalist and neo-liberal viewpoints.
This includes refusal to take action against climate change
or supporting the police, regulatory bodies and disregarding free software movements
for reasons of convenience.&lt;/p&gt;
&lt;p&gt;I'm taking about these things in rather vague terms because I want to avoid
drawing a definite line that people can't cross.
Really, I would argue that there's many ways to be a hacker.
I see issue and a danger to the movement,
when people attempt to "leave politics out of hacking" entirely.&lt;/p&gt;
&lt;p&gt;This includes fighting capitalism and discrimination against minorities.
Hackers, by definition, are the political left!
Anyone who isn't and still claims to be a hacker has successfully co-opted the word
and is attempting to undermine the movement for their own political gain.&lt;/p&gt;
&lt;p&gt;It's not always obvious how the existence of apolitical hackers impacts the movement
or the technologies that they build.
But just like Tech in general has racism and sexism problems,
so does the hacker movement.
Society does, really. There's no way to remove a community from time and space.
"Stuff" happened before we got here, and pretending that it didn't, is dangerous.&lt;/p&gt;
&lt;p&gt;I could talk about the impact of apoliticality on technology
and communities that are being built for a very long time but I really don't want to today.
Instead I want to focus on something else, something more positive.&lt;/p&gt;
&lt;h2&gt;A very political congress&lt;/h2&gt;
&lt;p&gt;I very much enjoyed this year's congress!&lt;/p&gt;
&lt;p&gt;Maybe in part that was because of the people I was attending it with this year ( 😉 )
but in no small part, it was also because of the general atmosphere around the event.
This isn't something only I noticed.
I had conversations about this with others,
who apparently also noticed this change from last year.&lt;/p&gt;
&lt;p&gt;The first thing you saw when entering the venue was a huge Antifa flag,
setting the tone of the rest of the event.
Apart from that there were a lot more assemblies this year,
many were dedicated to squatting, anarchy and fighting capitalism.
There were a few queer assemblies, scattered around the hall,
making it so that queer and leftist representations weren't all bundled in one spot
but were present all through the venue.
Even purely technical assemblies were surrounded by antifa flags and anarchist stickers and flyers.
This changed the atmosphere quite significantly.&lt;/p&gt;
&lt;p&gt;It wasn't perfect.
Just like last year, it was plagued by logistical problems,
some smaller, some larger.
There were people who had their stuff stolen.
There were speakers who made problematic jokes on stage.
There were still apolitial and centrist people present.
In fact, there were people complaining about C3 "having gotten so political",
which really is a good thing.
We want the centrist and right-leaning "hackers" (read: libertarians) to feel uncomfortable.&lt;/p&gt;
&lt;p&gt;But despite all that, the air, the general atmosphere of the event was different.&lt;/p&gt;
&lt;p&gt;I welcome this change.
And I hope that it sets a new tone for the CCC and the C3 in general.
I would very much enjoy going back next year
and finding out that the event had become even more overtly anarchist.&lt;/p&gt;
&lt;p&gt;Because we shouldn't forget our core motivation as hackers:
&lt;strong&gt;being gay, and doing crimes!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The only downside from 35C3? I don't really know what to think about birds anymore...&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Wed, 02 Jan 2019 00:00:00 +0100</pubDate><guid>tag:None,2019-01-02:/blog/hacking-is-political</guid><category>Blog</category><category>/dev/diary</category><category>CCC</category></item><item><title>Failure. Or: why Rust is probably the best programming language ever created</title><link>/blog/failure-or-why-rust-is-probably-the-best-programming-language-ever-created</link><description>&lt;p&gt;&lt;em&gt;This post is two stories.&lt;/em&gt; One is about accepting and recognising personal failure, reflecting and growing from it; the other is about an incredibly and seemingly endlessly powerful programming language, called &lt;em&gt;Rust&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In the summer of 2014&lt;/strong&gt; I started a project which was kind of insane. I knew it was insane, yet I embarked on that journey regardless. I wanted to write a password manager. I chose Ruby as a language because I didn't know many others and was – in more than one way – still a programmer novice.&lt;/p&gt;
&lt;p&gt;The details of development aren't too important. About 6-8 months into the project I had written something rather cool and functional. It wasn't very fast, the code base was a bit of a mess and I was having issues with packaging. But, at the core, I really liked what I had made, which had shifted from just being a password manager to being a universal, platform-independant secrets manager, close to a keychain. In my mind applications could write sensitive information into a "vault" which was managed by this project, without having to worry too much about access rights, authentication or anything else.&lt;/p&gt;
&lt;h1&gt;So far so good; this is how both stories start.&lt;/h1&gt;
&lt;p&gt;Over the next few years this project would take me over and, ultimately, destroy me. I had gotten it into my mind that the cryptography should have been handled by something more low-level, something more "advanced". I talked to people, I looked at languages and in the end, thinking I had more experience now, chose C++ to re-write the project in. &lt;em&gt;This was the beginning of the end.&lt;/em&gt; It took me another six months to get the basics done, getting caught up on nitty gritty details. &lt;/p&gt;
&lt;p&gt;I ended up switching to C, back to C++, &lt;em&gt;then back to C again&lt;/em&gt;, not being satisfied with the way that one or the other language handled things. And the scope was out of control. I didn't want to make a cute little secrets manager anymore. I wanted to make a database. It had transactions, sharding, multi-user access, backups, countless optimisations, run modes and even it's own SQL-like query language. I went completely overboard and lost all grasp of what it was I wanted to create. After literally years, re-writing the same parts of the code again and again, creating new libraries to handle even smaller tasks that had been completely trivial in Ruby, &lt;strong&gt;I stopped.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What this project had turned into wasn't maintainable. It didn't even really make any sense. It had no use-case, besides "being cool" and that wasn't really enough to motivate me anymore. I was also caught up with other work, getting involved with the Google Summer of Code 2016, then slowly fading work on the project into the background. This wasn't a conscious decision though. In my mind, I was just putting it on hold, learning from all of my failures and then trying myself again at another re-write. I didn't know that &lt;em&gt;not&lt;/em&gt; trying again would be the act of learning from it.&lt;/p&gt;
&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;As hackers, we are often compelled to take on the world. Everything seems plausible, sometimes trivial. We understand technology in a way that most people don't and in that, we gain confidence in our abilities past the point of reality. Hubris. We want to make things, break things, modify things. And we forget our own limitations, time and scope. We end up starting so many things that we never finish. Or we get obsessed with something that doesn't make any sense.&lt;/p&gt;
&lt;p&gt;It took me over 2 years to understand that I can't let my impulse to adventure drive the way I work. I love open source and I love working on things that are just &lt;em&gt;free&lt;/em&gt; and out in the open. I want to help build an ecosystem of tools and applications that help people, without any cost or baggage of being for a closed down system. But learning, that there were things that I can't do, that maybe the way that I viewed work, problems and how to tackle them was &lt;em&gt;fallable&lt;/em&gt;, that took some more time to understand. In the end, everything I did on this project was a collosal waste of time. It's still on my github, more as a reminder to myself of how failure works...&lt;/p&gt;
&lt;p&gt;It has nothing to do with not knowing how to solve a problem. It has nothing to do with failing to understand code or a language or a toolkit... It has &lt;em&gt;everything&lt;/em&gt; to do with not knowing how to limit a project, &lt;strong&gt;and when to stop...&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;This is the end of story one&lt;/h1&gt;
&lt;p&gt;It's been nearly a year since I worked on this project (or the 5th iteration of a re-write anyways), in the meantime I've worked on many small things, trying to keep in mind what I want to do, what is plausible and also useful. And in the meantime I've come into contact with a magical programming language: &lt;em&gt;Rust&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;I had started programming in Rust before, during a very stressful time in 2016. And I never managed to get into it much. This year was different though. The toolchain had matured and maybe I had also matured as a developer. And maybe I was in a better state of mind to learn new concepts. Whatever it was, I'm glad it happened.&lt;/p&gt;
&lt;p&gt;Rust is a systems programming language by Mozilla. It's a compiled and safe language which prevents segfaults and allows for &lt;em&gt;fearless concurrency&lt;/em&gt; (as they put it), without sacrificing speed. In fact, it runs &lt;a href="http://benchmarksgame.alioth.debian.org/u64q/rust.html"&gt;almost as fast as regular old C code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now though, that's only half the reason why Rust is amazing, and I will show in a moment how the first part of this story is in any way relevant.&lt;/p&gt;
&lt;p&gt;After creating a few smaller projects in Rust, I started thinking again about password managers. The landscape looks a little different now than it did in 2014, yet I'm still not 100% satisfied. Everything ends up being an add-on to keepass which, in my opinion, doesn't have a very good database layout or file format. And end-user applications are usually very complicated or badly designed. I know I have high standards when it comes to UI/UX design so please don't consider this slander about these projects. I just didn't want to use them and had been sticking to my Windows application running in a WINE for the last few years.&lt;/p&gt;
&lt;p&gt;Now I knew Rust. Because the amazing thing about Rust is only partially the language. The other half is the entire toolkit that comes with it. From a built-in version manager to a kickass package manager, an ecosystem of &lt;code&gt;crates&lt;/code&gt; that can be easily included, following the UNIX philosophy of enabling you to do small things, in good ways, yet somehow always fitting together.&lt;/p&gt;
&lt;p&gt;I remembered what I had thought about before. Limitation of scope, accepting limitation of time and limits also in my own abilities. And I started writing a project very close to what it had once been in Ruby. And within a week or so, I was close to the feature set of the version I had finished, before beginning my descent into madness. It took me a week of collecting external crates, writing a few hundred lines of code myself, playing around with different crypto backends and there I was, in the process of building something cool again.&lt;/p&gt;
&lt;p&gt;Rust makes it incredibly simple to do rapid prototyping. Yes, the language is very strict sometimes. Yet it has this feeling of "throwing shit against the wall" and seeing what sticks. With the added benefit that there are compile-time checks that make sure that there are no serious issues with your program. You can still write bad code, it just seriously limits the damage you can do. And that makes it incredibly fun to write with.&lt;/p&gt;
&lt;h1&gt;What's the point of all this?&lt;/h1&gt;
&lt;p&gt;Well, first that I love Rust 😝.&lt;/p&gt;
&lt;p&gt;But secondly that sometimes failure looks different than what we might expect. It's not about failing on a technical but either on a social or planning level. And maybe that this is something we should talk about and foster in the hacker community.&lt;/p&gt;
&lt;p&gt;Rust is an amazing language for many things but it also has it's limits. There are countless people in the hacker culture who stick to their technologies because they feel familiar, dragging others into their little bubbles because they want to expand their influence, never considering if what they're advocating is sensible or scalable.&lt;/p&gt;
&lt;p&gt;This isn't just something we (as a culture) do with tools, it also happens on a social level. And in the end, shouldn't we all strife to learn new things, broaden our horizons and, last but not least, choose the right tool, for the right job?&lt;/p&gt;
&lt;p&gt;Sometimes a new technology can enable us to break out of our bubble and achieve something that we previously thought impossible.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Sun, 11 Mar 2018 00:00:00 +0100</pubDate><guid>tag:None,2018-03-11:/blog/failure-or-why-rust-is-probably-the-best-programming-language-ever-created</guid><category>Blog</category><category>/dev/diary</category><category>reflections</category><category>programming</category><category>rust</category></item><item><title>Rebuilding my Website (again)</title><link>/blog/rebuilding-my-website-again</link><description>&lt;p&gt;It's winter, rebuilding my website is a tradition...right? &lt;strong&gt;Happy new year everybody.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This has been a long time coming. I've not really been happy with the way my website looked for a while and have been playing around with new designs for the past few months. I also took that opportunity to throw out a few old articles, fix formatting on others and generally do house-keeping.&lt;/p&gt;
&lt;p&gt;The whole thing is still using &lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt; to generate pages but now with a completely new theme and new plugins 🎉&lt;/p&gt;
&lt;p&gt;This re-design also decreases complexity. The old theme was massively too complicated and I've now taken it down to 3 (or 4?) templates. Working around the old theme and what Pelican expected was an interesting experience. Especially since it felt less like building a website and more like working with a game engine where small changes make lots of magic happen and &lt;em&gt;voilá&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;There are a few things I want to write about...&lt;em&gt;soon&lt;/em&gt;. Until then, there is an easteregg hidden somewhere. Let's see who finds it first 😉&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Wed, 03 Jan 2018 01:31:00 +0100</pubDate><guid>tag:None,2018-01-03:/blog/rebuilding-my-website-again</guid><category>Blog</category><category>/dev/diary</category><category>meta</category></item><item><title>Dabbling with Moonscript</title><link>/blog/dabbling-with-moonscript</link><description>&lt;p&gt;&lt;img alt="Lua means moon in portuguese" src="/images/lua_moon_banner.png"&gt;&lt;/p&gt;
&lt;p&gt;Recently I've started learning/ using Moonscript. It's a language that compiles to &lt;a href="https://www.lua.org/"&gt;lua&lt;/a&gt; and as such can run in the LuaJIT, an alternative lua engine which allows very easy and &lt;em&gt;fast&lt;/em&gt; ffi calls into native code. This makes lua code capable of writing very performant applications and games that use native rendering, window creation or general libraries.&lt;/p&gt;
&lt;p&gt;But in my opinion lua has always felt a bit cumbersome. I use awesomewm so I had to write it occasionally to customise my UI layout. And this is where Moonscript comes in. It's a lot of syntactic sugar on top of lua as well as some other concepts such as object orientation which lua just plain out doesn't have. And while yes, you can write good code without OO (&lt;em&gt;cough&lt;/em&gt;  &lt;strong&gt;C&lt;/strong&gt; &lt;em&gt;cough&lt;/em&gt;) it is a nice tool to have in your pocket, especially when writing GUI applications or games.&lt;/p&gt;
&lt;h2&gt;The language&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Thing&lt;/span&gt;
  &lt;span class="nv"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Thing&lt;/span&gt;
  &lt;span class="nv"&gt;say_name:&lt;/span&gt; &lt;span class="nf"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;Hello, I am #{@name}!&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;MoonScript&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;say_name&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see Moonscript is an indentation based language which (in my opinion) combines syntactic elements from lua and ruby together. In the snippet above (which is from the &lt;a href="http://moonscript.org/"&gt;moonscript website&lt;/a&gt;) you can see classes, inheritance as well as the &lt;code&gt;with&lt;/code&gt; keyword which allows you to initialise/ work with objects without typing it's variable name over and over again.&lt;/p&gt;
&lt;p&gt;If you want to learn more about the language, I can only recommend you have a look at the &lt;a href="https://github.com/leafo/moonscript/wiki/Learn-MoonScript-in-15-Minutes"&gt;Moonscript in 15 minutes guide&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;How to use it&lt;/h2&gt;
&lt;p&gt;You can just write Moonscript files, add &lt;code&gt;#!/usr/bin/env moon&lt;/code&gt; to them and get going. Obviously that's pretty cool for little scripts that you just want to get going. But not so great for larger applications because a) you don't have access to &lt;code&gt;ffi&lt;/code&gt; via luaJIT and b) it adds additional startup cost.&lt;/p&gt;
&lt;p&gt;So instead for my projects so far (which so far are a &lt;a href="https://github.com/spacekookie/dinodino"&gt;game&lt;/a&gt; and a desktop app) I use a &lt;code&gt;Makefile&lt;/code&gt; to build and run the Moonscript compiler and then execute the &lt;code&gt;init.lua&lt;/code&gt; with luajit.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;SOURCES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;wildcard&lt;span class="w"&gt; &lt;/span&gt;*.moon&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;wildcard&lt;span class="w"&gt; &lt;/span&gt;**/*.moon&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;LUAOUT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;SOURCES:.moon&lt;span class="o"&gt;=&lt;/span&gt;.lua&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;

&lt;span class="nf"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;

&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;
&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;LUAOUT&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;%.lua&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;%.&lt;span class="n"&gt;moon&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;moonc&lt;span class="w"&gt; &lt;/span&gt;$&amp;lt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;luajit&lt;span class="w"&gt; &lt;/span&gt;init.lua
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;So...I'm kinda excited about this. Most of the code I write is either in C or Java (depending on what exactly I'm doing). And those two strongly typed and compiled languages have served me well and will continue to be my go-to solutions for a lot of problems.&lt;/p&gt;
&lt;p&gt;But I've long been looking for a dynamicly typed, interpreted/ just-in-time compiled language that I can use for anything from little scripts to medium-sized desktop applications. I used to use python for this but have recently (over the last 6-9 months) fallen out of love and developed a rather passionate dislike of it and it's ecosystem.&lt;/p&gt;
&lt;p&gt;My current project will get it's own little article at some point but I don't mind teasing the progress here. I'm writing a new UI for redshift which works with X11 linux backends and is heavily inspired by f.lux on MacOS. It's written in moonscript, with my own forked version of redshift (which I call &lt;a href="https://github.com/spacekookie/libredshift"&gt;libredshift&lt;/a&gt;). It's on &lt;a href="https://github.com/spacekookie/redshift_ctrl"&gt;github&lt;/a&gt; and licensed under MIT.&lt;/p&gt;
&lt;p&gt;Hope I've made you a little curious about Moonscript :)&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Sat, 06 May 2017 11:55:00 +0200</pubDate><guid>tag:None,2017-05-06:/blog/dabbling-with-moonscript</guid><category>Blog</category><category>/dev/diary</category><category>moonscript</category><category>programming</category></item><item><title>LibGDX interface containers</title><link>/blog/libgdx-interface-containers</link><description>&lt;p&gt;&lt;strong&gt;Let me tell you a factual statement&lt;/strong&gt;: UI programming is terrible&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Let me tell you an even more factual statement&lt;/strong&gt;: UI programming in LibGDX is even more terrible&lt;/p&gt;
&lt;p&gt;I am a big fan of LibGDX. It's a really nifty library/ framework to get started with game development if you're more comfortable inside a code editor than a full blown game engine that is more targeted towards designers and artists. And I put my money where my mouth is: I have a series about LibGDX development for beginners on this blog and work almost exclusively with it when it comes to my own projects.&lt;/p&gt;
&lt;p&gt;Yet, there is something that bothers me and there didn't seem to be a great solution to fix it. UI code structure. In this post I want to highlight a utility I have written for LibGDX which is very easily embeddable into your existing projects which will you help structure UI code more efficiently.&lt;/p&gt;
&lt;h1&gt;The root problem&lt;/h1&gt;
&lt;p&gt;The reason I dislike UI programming with LibGDX is that it usually results in very long code files or passing dozens of parameters into sub-classes that are needed to update the UI for button presses, etc.&lt;/p&gt;
&lt;p&gt;This goes so far that I have written an editor for game assets before just to realise that (once the development was complete) it had become completely unmaintainable and I had to start from scratch with better structure. It is incredibly easy to just throw out a UI design with Scene2D and LibGDX but unfortunately it is equally easy to produce very bad code which will turn into a big spaghetti mess.&lt;/p&gt;
&lt;p&gt;Let's look at an example problem that I wanted to solve.&lt;/p&gt;
&lt;p&gt;&lt;img alt="LibGDX UI design problem" src="/images/libgdx_ui/01_base_problem.png"&gt;&lt;/p&gt;
&lt;p&gt;Looking at this structure we have three main components that interact with each other. We have a class that handles UI logic (setting up actors in tables, adding listeners, etc), we have a window state which in the particular case which made me write an alternative was a "Lobby Handle" which coordinated what players were going to enter a match, the map, game mode and if everybody in the multiplayer match was set to "Ready". Lastly we have the actual network signal handlers that listen to TCP/ UDP packets and execute code to write/ read from the window state as well as update UI elements.&lt;/p&gt;
&lt;p&gt;Implementing this structure with Scene2D and LibGDX will result in a lot of very ugly code. Because the network signals need to know everything about the UI (how it is structured, etc). And our window state can be written to by two different sources which means that we need to mutex it to avoid race conditions.&lt;/p&gt;
&lt;h1&gt;Maybe a solution&lt;/h1&gt;
&lt;p&gt;So, what was I trying to solve? First a bit of limitation of scope. Because a lot of UI problems have been solved over and over again and usually at the cost of runtime performance or with a &lt;em&gt;lot&lt;/em&gt; of extra code.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;UI code doesn't have to be embedded in a screen&lt;/li&gt;
&lt;li&gt;All UI code can access the shared context of the screen&lt;/li&gt;
&lt;li&gt;UI elements can update each other&lt;/li&gt;
&lt;li&gt;Clean API that can be called on from anywhere (with a reference to the handle) that triggers range of functions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So with that in mind, this is what I did.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyUIHandle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;extands&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UIHandle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UI_BASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;PLAYER_LIST&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/** Initialiser block for new objects */&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;registerHandle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PlayerList&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PLAYER_LIST&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// ... more handles&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;initialise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlayerList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UIContainer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;initialise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Define more API here ...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When we initialise a new &lt;code&gt;UIHandle&lt;/code&gt; the initialiser block will create our &lt;code&gt;PlayerLists&lt;/code&gt; and register them with the &lt;code&gt;UIHandle&lt;/code&gt;. That code is hidden away from you. You can see that we're implementing a different enum type that we overload with values so that we can address submodules via a compile-time checkable value (such as enums). From inside (and outside) this class &lt;code&gt;UIContainer's&lt;/code&gt; are available via &lt;code&gt;handle.get(UI.SUB_HANDLE)&lt;/code&gt;. Obviously keeping your enum labels short will make your function calls snappier :)&lt;/p&gt;
&lt;p&gt;The following graphic will sort-of explain the layout in more detail.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Super UI fixing attempt" src="/images/libgdx_ui/02_ui_structure.png"&gt;&lt;/p&gt;
&lt;p&gt;What you might also notice is that the &lt;code&gt;UIHandle&lt;/code&gt; has an initialise function with variadic parameters while the &lt;code&gt;UIContainer&lt;/code&gt; class only takes a stage. That is because window context is stored once in the &lt;code&gt;UIHandle&lt;/code&gt; and then accessable from all &lt;code&gt;UIContainer&lt;/code&gt; classes. This way we only need to do the inversion of control pattern once instead of for every sub-component.&lt;/p&gt;
&lt;p&gt;You can keep the &lt;code&gt;UIContainer&lt;/code&gt; classes outside this code-file. Then you might however want to provide a construct that does another inversion of control so that an external &lt;code&gt;UIContainer&lt;/code&gt; can access the context provided via initialise!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlayerList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UIContainer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyUIHandle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;PlayerList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyUIHandle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now let's talk about that public API. In our original example we wanted to have networking code update some UI elements. And we want UI elements to update other UI elements. So first of all, we keep context in each &lt;code&gt;UIContainer&lt;/code&gt; about what UI elements are accessable to it. So what we can do in every of our submodules is this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PLAYER_LIST&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="na"&gt;updatePlayers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It also means that if we get new data from – say – a network socket or AI simulation, we can very easily update data in some random UI element. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PLAYER_LIST&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="na"&gt;populate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So all in all, we have solved the following problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We have access to all game state in the UI code without passing too many parameters into lots of sub-classes&lt;/li&gt;
&lt;li&gt;UI code can be moved into lots of files for easier understandability&lt;/li&gt;
&lt;li&gt;Context isn't duplicated&lt;/li&gt;
&lt;li&gt;UI code can update other UI code without needing a direct reference to it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The individual &lt;code&gt;UIContainer&lt;/code&gt; instances are essentially independant of each other via dependency injection.&lt;/p&gt;
&lt;p&gt;This library isn't done yet. Most of this is kinda hacked together to fit into &lt;strong&gt;my&lt;/strong&gt; game. But I'm interested in making it more generic and putting it on Github. Especially because I can see myself using it again in the future.&lt;/p&gt;
&lt;p&gt;Hope this might be useful to somebody out there. If you have questions, comments, hatemail...&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/spacekookie"&gt;Twitter&lt;/a&gt; or &lt;a href="mailto:kookie@spacekookie.de"&gt;E-Mail&lt;/a&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Tue, 24 Jan 2017 00:14:00 +0100</pubDate><guid>tag:None,2017-01-24:/blog/libgdx-interface-containers</guid><category>Blog</category><category>/dev/diary</category><category>libgdx</category><category>game dev</category><category>java</category></item><item><title>Post 33C3, what next?</title><link>/blog/post-33c3-what-next</link><description>&lt;p&gt;Howdy everybody,&lt;/p&gt;
&lt;p&gt;I just came back from the annual hacker conference in Hamburg, Germany known as the "Chaos Communication Congress" (or CCC for short). It was the first time I was there for the entire venue and the first time I was able to go at all since &lt;em&gt;2008&lt;/em&gt;. So yay!&lt;/p&gt;
&lt;p&gt;It was a lot of fun and I have a lot of nice memories to hold onto now. I talked to a lot of interesting people, learned new things, got inspired to do new things and continue on old things.&lt;/p&gt;
&lt;p&gt;More importantly, I loved the chance to get in touch with some other women in the tech industry (via Haecksen &amp;amp; Queer Feminist Geeks), talk about problems, attempt to come up with solutions and just generally rant about things :)&lt;/p&gt;
&lt;p&gt;I also found out that I am in no way, shape or form a dancing person. Although electronic club music is fun!&lt;/p&gt;
&lt;h1&gt;Some talks I went to&lt;/h1&gt;
&lt;p&gt;Following is a non-comprehensive list of the talks I went to. I am filling this from memory, so some talks might have been missed or dropped. And maybe I'll just edit them in later without anyone ever knowing.&lt;/p&gt;
&lt;h2&gt;&lt;a href="https://fahrplan.events.ccc.de/congress/2016/Fahrplan/events/8127.html"&gt;How Do I Crack Satellite and Cable Pay TV?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A really quite epic lecture about using glitching to extract keys from a very dated security layout. Not that anyone should do this (it's not worth doing it anyways...never anything good on) but it will teach you a lot of stuff about hardware security&lt;/p&gt;
&lt;h2&gt;&lt;a href="https://fahrplan.events.ccc.de/congress/2016/Fahrplan/events/8314.html"&gt;Bootstraping a slightly more secure laptop&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A talk about the flip-side of TAILS which aims to introduce trusted computing into a world where the machine can't be trusted. HEADS on the other hand uses coreboot and cleverness to create a verifiable machine environment to build an OS on top of. Made me want to get an old thinkpad on ebay to play with 😊&lt;/p&gt;
&lt;h2&gt;&lt;a href="https://fahrplan.events.ccc.de/congress/2016/Fahrplan/events/7925.html"&gt;The Nibbletronic&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A relatively short talk about the creation of a musical instrument. Learning by doing and failing. Quite interesting for me as a hardware designer (as a hobbyist) but also a musician.&lt;/p&gt;
&lt;h2&gt;&lt;a href="https://fahrplan.events.ccc.de/congress/2016/Fahrplan/events/7969.html"&gt;Shut Up and Take My Money!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you have a bank account with N26...stop having a bank account with N26. Their security is absolutely horrible. And while, yes, all of these security issues have been fixed, it shows a rather lacking attitude towards security from their engineering team. Best demonstration of client-side security gone wrong. And why ReST APIs are fucking aweful!&lt;/p&gt;
&lt;h2&gt;&lt;a href="https://fahrplan.events.ccc.de/congress/2016/Fahrplan/events/8014.html"&gt;Untrusting the CPU&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This was a great talk given by a close friend of mine about one of his super crazy projects. The idea being to construct an FPGA powered PCI-E device for laptops and/ or desktop computers that intercepts messages to the display, encodes and decodes text into them to provide an interface for encrypted messages without using the CPU. It's really quite interesting and I can't wait to see what he does with it.&lt;/p&gt;
&lt;h2&gt;&lt;a href="https://fahrplan.events.ccc.de/congress/2016/Fahrplan/events/7975.html"&gt;Making Technology Inclusive Through Papercraft and Sound&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of my favourite talks was about an engineering toy kit that was aiming to be more inclusive. The problem it attempts to tackle are the incredible low numbers of women in computer science and engineering (significantly lower than in other scientific fields). There are a lot of reasons why women aren't well represented in the fields and they are all cultural. This talk was about trying to change the culture around teaching people about electronics and code to be more inclusive towards groups of people (mostly girls/ women) who would otherwise be missed.&lt;/p&gt;
&lt;p&gt;I really enjoyed the talk on a lot of different levels. One was the technical aspect of creating a childrens toy on the cheap that is inclusive and universally programmable through audio encoding. Quite worth a watch.&lt;/p&gt;
&lt;p&gt;I don't think that just with projects like this the culture around women in tech will change. But it's a start. What we realistically need is a change in culture throughout all layers of society. I think the problems around women in tech are quite complicated. And unfortunately usually result in a bunch of assholes starting to shout either about how feminism is evil or how diversity isn't important. And biases aren't actually thaaaaat bad, right? 😝&lt;/p&gt;
&lt;p&gt;I could rant here forever and it's questionable how many people would actually care 😅 I can recommend this talk. Let's leave it at that :)&lt;/p&gt;
&lt;h2&gt;&lt;a href="https://fahrplan.events.ccc.de/congress/2016/Fahrplan/events/8406.html"&gt;The Moon and European Space Exploration&lt;/a&gt;, &lt;a href="https://fahrplan.events.ccc.de/congress/2016/Fahrplan/events/7942.html"&gt;Interplanetary Colonization&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Those were just the first two talks from a series of space talks. The first one was from one of the heads of ESA about their plans to colonise the moon for profit! And science of course... It was quite funny and definately worth watching.&lt;/p&gt;
&lt;p&gt;The second one I almost liked more, though mostly the first part of it. Liz George manages to explain incredibly well in a very short amount of time what challenges exist when discovering exo-planets. The second part (by somebody else) is a bit more vague about how to actually get there and is less science, more fiction. But hey 😝&lt;/p&gt;
&lt;h1&gt;Going into 2017&lt;/h1&gt;
&lt;p&gt;So in short: 33C3 was pretty epic! And I honestly can't wait for next year. It's not clear yet where it will be held but it will be epic non-the-less. And who knows, maybe I have a talk to hold by then 😊&lt;/p&gt;
&lt;p&gt;Which brings me to this year. Last year was fucking shitty. Politically...On a personal level it actually went quite well. And I got a lot of shit done. I did Google Summer of Code, I made &lt;em&gt;huge&lt;/em&gt; progress on my game project (yes, I will post about that at some point). And especially in the last months of the year, I redesigned and rerouted the Open Plantb0t board. On january 1st, 2017 the revision A2 design went into production.&lt;/p&gt;
&lt;p&gt;I hope to get all my parts together soon and build up a second prototype series which (hopefully) works better than the last 😉 I will keep y'all updated on that.
pel
Until then, I hope you've had a happy new years eve and not an all too terrible year...yet 😉&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Tue, 03 Jan 2017 12:28:00 +0100</pubDate><guid>tag:None,2017-01-03:/blog/post-33c3-what-next</guid><category>Blog</category><category>/dev/diary</category><category>c3</category><category>ccc</category></item><item><title>Winter update</title><link>/blog/winter-update</link><description>&lt;p&gt;Howdy everybody!&lt;/p&gt;
&lt;p&gt;As the year is winding down and we're all getting ready for the jump to take us out of what has (in my opinion) been a &lt;em&gt;very&lt;/em&gt; shitty year, I looked at my blog and could only shake my head.&lt;/p&gt;
&lt;p&gt;I had moved this over from Wordpress to Pelican and basically replicated all of the layouts to the extent that some of Pelicans own functionality had to be abused to make it work. But as I kept publishing things on here I realised that most of the features I had implemented went unused.&lt;/p&gt;
&lt;p&gt;And so, for the last few days I have tweaked the layout (and design - as some might notice) to be a bit more traditional again.&lt;/p&gt;
&lt;p&gt;I was also considering to change theme but after not finding anything I liked I decided to hack the fuck out of my current one instead. You can check out all of my horrible changes &lt;a href="https://github.com/spacekookie/nest"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I've also finally done some stuff that I've wanted to do for ages - such as pimping up the front page, adding a proper projects page and go through some of my old tutorial series, fix their formatting (yea right "perfect wordpress import...") and update them to newer API's of libraries. Some articles have just been dropped because I would have had to re-work their formatting and they were no longer relevant. Stuff will slowly be introduced again, with proper formatting 😊&lt;/p&gt;
&lt;h2&gt;Everything else&lt;/h2&gt;
&lt;p&gt;In the terms of literally everything except my blog: I'm looking forward to the &lt;strong&gt;33C3&lt;/strong&gt;. I'll be joining with the c-base assembly. My first congress in almost a decade! Expect maybe an update from that. And maybe there might be some christmas hacking. It's always more fun to do silly RGB LED stuff if it ends up annoying people on the tree!&lt;/p&gt;
&lt;p&gt;Also, with the blog now in a bit better shape I will try to keep a closer journal of what I'm doing. But hey...no promises, right? 😉&lt;/p&gt;
&lt;p&gt;I shall leave you with this piece of relaxing GIF.&lt;/p&gt;
&lt;p&gt;&lt;img class="original" src="http://i.imgur.com/KZquOZM.gif" /&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Fri, 02 Dec 2016 10:43:00 +0100</pubDate><guid>tag:None,2016-12-02:/blog/winter-update</guid><category>Blog</category><category>/dev/diary</category><category>meta</category></item><item><title>What I have done in GSoC 2016</title><link>/blog/what-i-have-done-in-gsoc-2016</link><description>&lt;p&gt;Google Summer of Code is coming to an end. And as the final bugs are getting squashed and more code is being prepared for the big merge, I am sitting here, trying to think of how to represent my work.&lt;/p&gt;
&lt;p&gt;I thought I would write up a little blog post, explaining what I've done and what still remains to be done. &lt;/p&gt;
&lt;h1&gt;The TLDR&lt;/h1&gt;
&lt;p&gt;My main contributions are all available &lt;a href="https://github.com/spacekookie/qaul.net/commits/qaul_crypto?author=spacekookie"&gt;here&lt;/a&gt; (spacekookie/qaul.net on the &lt;code&gt;qaul_crypto&lt;/code&gt; branch). I did a lot of small commits. Most of my code can be found in this &lt;a href="https://github.com/spacekookie/qaul.net/tree/qaul_crypto/src/libqaul/crypto"&gt;sub-directory&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In addition to that I ported an existing project (from python) to C to be relevant for future front-end endevours of the client. It's called &lt;a href="https://github.com/spacekookie/librobohash"&gt;librobohash&lt;/a&gt;. I didn't end up finishing the port because there were more pressing issues in qaul.net and the UI was delayed.&lt;/p&gt;
&lt;p&gt;While most of my work has been in hidden backend systems there is a demo you can run. The source compiles and has been tested under Linux (Ubuntu 16.04 and Fedora 24) and is located under the &lt;code&gt;src/client/dbg/&lt;/code&gt; directory. The demo creates two new users (to simulate communication between two nodes), adds the public keys to the keystore and then continues to sign and verify messages. If the demo returns lots of "0" and "OK" it went okay 😊&lt;/p&gt;
&lt;p&gt;Feel free to play with the demo; for example, switch out &lt;code&gt;message&lt;/code&gt; for &lt;code&gt;fakemessage&lt;/code&gt; during verification 😊 The source for the demo can be found under &lt;code&gt;src/libqaul/qcry_wrapper.c&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;The good (aka what I have done)&lt;/h1&gt;
&lt;p&gt;&lt;img class="dual" src="/images/gsoc/02_cryptoui.png" align="left"&gt;&lt;/p&gt;
&lt;p&gt;The two main components that I've written during GSoC2016 are internally referenced as &lt;code&gt;qcry_arbit&lt;/code&gt; and &lt;code&gt;qcry_context&lt;/code&gt;. They are two modules that make up the new crypto module in qaul.net.&lt;/p&gt;
&lt;p&gt;As I explained in my first blog post on the &lt;a href="http://blog.freifunk.net/2016/gsoc2016-wrapping-crypto-module-qaulnet"&gt;Freifunk blog&lt;/a&gt; the Arbiter provides a static API for the rest of the library (libqaul) to interact with the crypto module. &lt;/p&gt;
&lt;p&gt;The context holds the actual magic of holding user keys, signing and verifying messages and (theoretically) encrypting messages as well.&lt;/p&gt;
&lt;p&gt;Possible with this API at this time is to create users, to sign messages with a users private key and to verify messages that are sent to you from other users. Originally it was planned to split the arbiter into the actual API and a dispatcher which would allow for concurrent access to the inner functions. However it was established through tests that the design was overkill and was thus scrapped.&lt;/p&gt;
&lt;p&gt;A keystore was added in addition to the user store already existing in qaul.net to provide an easy way to store public keys (mapped against fingerprints) that are received from flood events on the network.&lt;/p&gt;
&lt;p&gt;In total the crypto submodule adds another ~2.2k lines of code to the project.&lt;/p&gt;
&lt;h1&gt;The bad (aka what I haven't yet done)&lt;/h1&gt;
&lt;p&gt;So far completely un-implemented is encryption. Unfortunately working with the crypto library selected for the task turned out to be more challenging than expected. With almost no documentation and a few very niche examples I basically went through the library line-by-line to understand how it worked. &lt;/p&gt;
&lt;p&gt;As such, my focus was set on signature exchanges at first because the verifiability of messages and the change to address users by their fingerprints was deemed more important.&lt;/p&gt;
&lt;p&gt;My contributions to qaul.net won't end with the end of Summer of Code. The function stubs are already provided and I plan on implementing the encryption features in the coming weeks.&lt;/p&gt;
&lt;h3&gt;The ugly (aka what I can't do yet)&lt;/h3&gt;
&lt;p&gt;Signatures (and also encryption) of private messages (so messages that aren't flooded to everybody) is currently impossible. This is due to the way that the communication system in qaul.net works.&lt;/p&gt;
&lt;p&gt;I have talked to my mentor and he said that they were currently in the process of re-writing the communication sub-system in libqaul. This means two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I need to wait for those changes to be done until I can finish what I set out to do&lt;/li&gt;
&lt;li&gt;Some of the code I wrote (hooking into the current communication system) is being made obsolete 😞&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;In conclusion&lt;/h1&gt;
&lt;p&gt;What I can say is this: qaul.net has gotten a very big step closer to becoming a more secure network of communication. The crypto submodule is tested and easy to use. What might happen is that parts of the code get merged (the crypto submodule itself) without merging any of the code that hooks into the communication stack.&lt;/p&gt;
&lt;p&gt;I had a lot of fun working on this project and I am looking forward to more contributions. I have a few cool ideas that I want to discuss with the rest of the team and I am glad that I participated in the Google Summer of Code.&lt;/p&gt;
&lt;p&gt;I was interested in open source before and I contributed to my own projects on github. But the experience I gained this summer will be helpful for me, not just for my own work, but to be less reluctant to join other developer communities.&lt;/p&gt;
&lt;p&gt;And I look forward to seeing my code get merged into qaul.net 😊&lt;/p&gt;
&lt;p&gt;Read you soon,&lt;/p&gt;
&lt;p&gt;~Kate&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Fri, 19 Aug 2016 18:13:00 +0200</pubDate><guid>tag:None,2016-08-19:/blog/what-i-have-done-in-gsoc-2016</guid><category>Blog</category><category>/dev/diary</category><category>gsoc2016</category></item><item><title>First steps...baby steps</title><link>/blog/first-stepsbaby-steps</link><description>&lt;p&gt;So it's been almost two months, the community bonding period has passed, blog posts were written, talks held and slowly but surely I'm working myself into the qaul.net codebase.&lt;/p&gt;
&lt;p&gt;It's always weird joining a larger project and seeing established build setups, code conventions or generally things where your first thought is "I would have done that differently...". But it's really fun.&lt;/p&gt;
&lt;p&gt;I'm currently working myself into &lt;a href="https://tls.mbed.org/"&gt;mbed.tls&lt;/a&gt; which is the crypto library which was chosen to power the cryptographic backend for libqaul (which powers qaul.net).&lt;/p&gt;
&lt;p&gt;That includes some code that will probably not make it into a later version of my branch: the debugger.&lt;/p&gt;
&lt;h1&gt;The De-bugger?!&lt;/h1&gt;
&lt;p&gt;&lt;img alt="Debugger Pro 2016" src="/images/gsoc/01_debugger.png" title="Debugger"&gt;&lt;/p&gt;
&lt;p&gt;Well...debuger might be a bit of a strong word, it's basically a way to develop core functions of qaul.net without having to start a GUI, going through NetworkManager dialup or oslr bootup.&lt;/p&gt;
&lt;p&gt;There I am currently busy writing a wrapper around a new namespace added to libqaul: &lt;code&gt;qcry&lt;/code&gt; (short for qaul crypto) and properly integrate all the mbed.tls sources into the library so they can be accessed by libqaul. The idea being that I don't have to leave vim and the terminal to develop on the core cryptographic components such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Key generation&lt;/li&gt;
&lt;li&gt;Identify generation (with private key fingerprints)&lt;/li&gt;
&lt;li&gt;Identity verification&lt;/li&gt;
&lt;li&gt;???&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Only in the last step of the last bulletin do I actually have to involve the GUI of qaul.net. And until that point I wish to not come in contact with it (if avoidable).&lt;/p&gt;
&lt;p&gt;So most of next week will be getting to know mbed-tls as I have never worked with it before. But hey...can't be worse than the gcrypt documentation¹ 😂&lt;/p&gt;
&lt;p&gt;Hope to read you soon with more updates (probably rants).&lt;/p&gt;
&lt;p&gt;Kate o/&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;¹I am sure I will eat my words in 4 weeks&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Thu, 02 Jun 2016 19:56:00 +0200</pubDate><guid>tag:None,2016-06-02:/blog/first-stepsbaby-steps</guid><category>Blog</category><category>/dev/diary</category><category>gsoc2016</category></item><item><title>I got accepted to GSoC 2016</title><link>/blog/i-got-accepted-to-gsoc-2016</link><description>&lt;p&gt;&lt;img alt="Acceptence Mail" src="/images/gsoc/00_acceptance.png" title="Acceptence Mail"&gt;&lt;/p&gt;
&lt;p&gt;The title should be self explanatory about that one 😊&lt;/p&gt;
&lt;p&gt;But let me go back a little bit. A couple of weeks ago I sat in the basement of my local hackerspace talking to a friend about crypto when somebody joined the conversation, asking if I was a student and if I might be interested in Google Summer of Code.&lt;/p&gt;
&lt;p&gt;After I looked up the project and familiarised myself with what had to be done, I thought it would be interesting to try to apply. And so I did. I wrote a long-ish proposal of what I wanted to do, how I would do it and when exactly I would acomplish my goals. (You can read my original proposal &lt;a href="https://storage.googleapis.com/summerofcode-prod.appspot.com/gsoc/core_project/doc/1458924075_GSOCProposal-KatharinaSabel.pdf?Expires=1461863360&amp;amp;GoogleAccessId=summerofcode-prod%40appspot.gserviceaccount.com&amp;amp;Signature=h0y5Nzi7llFNWKzt9%2BLGLvxcAPZ%2FaO7ni1ZyRDA3uFi6PD%2BDBmtIB6RJAr4Ulhv6fe64IFyB%2FI9iuVIYWIInYTmN7pZ9aUxw6TgxgFYguIywfcE2yUZ4o5UKb0PUbwI0Pu7o6mq%2BzSDXqlegpVOgujQ9k2QuTg1T1CqGzSi%2FnC4u6H0mB%2BxzWGGpoBC6rFwkKM1S70gE7hJ0EZpgYWr9H9zKPcwrfPtx99zqb488sH6STGYJf4tFrDRnnr57k2zbSN%2BO17chZtVBjGUYrKoyU6B%2FGB8MexFE6rmYaTCr5AjgqGWm97VCCwZkpHbRiTtFH5yT825G9%2FkRPYHkxsPnCw%3D%3D"&gt;here&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;In the meantime I actually had a sit-down with my mentor (the person joining the conversation in that basement) and made further plans how to implement things.&lt;/p&gt;
&lt;p&gt;And so this is it. The next month or so I will have time to get to know the code base of the project (although I partially already have), meet more people from the community and generally get into the rythm of what GSoC is.&lt;/p&gt;
&lt;p&gt;I will be posting three blog posts on the official &lt;a href="http://blog.freifunk.net/"&gt;Freifunk Blog&lt;/a&gt;, one in a couple of days/ weeks, one in the height of the project and one that will go into the aftermath of the project.&lt;/p&gt;
&lt;p&gt;But in the meantime I will be keeping my blog up to date about what I am doing, how things are going, my challenges and things I learn.
In the hopes that people might find it useful and lean things from it. Or just to save my insane ramblings in some narcissistic pleasure...to think that I am relevant in the world 😜&lt;/p&gt;
&lt;p&gt;Read you soon,&lt;/p&gt;
&lt;p&gt;Kate&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Wed, 27 Apr 2016 18:47:00 +0200</pubDate><guid>tag:None,2016-04-27:/blog/i-got-accepted-to-gsoc-2016</guid><category>Blog</category><category>/dev/diary</category><category>gsoc2016</category></item><item><title>Open Plantbot – Rev A</title><link>/blog/open-plantbot-rev-a</link><description>&lt;p&gt;Spring is coming in Berlin and thus my thoughts – as every year – are with plants and growing them. I live in an appartment with a tiny tiny balcony so I don't have much space but that has never stopped me from wanting to cram as many plants into the space as possible to the point of starting nuclear fusion.&lt;/p&gt;
&lt;p&gt;In addition to that I have a few house-plants and very water-sensitive trees in my appartment. My current approach is to go around with a jug of water every couple of days and water them individually – making sure the soil has a certain moisture and doesn't exceed a certain limit – but I've always had the dream of being able to automate away as much as possible. That's where the idea of &lt;code&gt;Plantb0t&lt;/code&gt; started. And I want to tell you a little bit about it.&lt;/p&gt;
&lt;p&gt;The basic idea is to have a little controller in each plant-pot that measure the moisture of the soil and reports that back to me via an ESP-12 SOM (System on a Module). The ESP has WiFi capabilities and would log to an MQTT server on my home media server. This way (when I'm at home – none of that IoT shit) I can see how my plans are doing.&lt;/p&gt;
&lt;h1&gt;Current state&lt;/h1&gt;
&lt;p&gt;So that's what Revision A of Plantb0t is. I also added a second sensor slot which is meant to be populated by a temperature sensor but could theoretically house a second moisture sensor. In the end the probes are only sticks in the ground that have a resistance between them.&lt;/p&gt;
&lt;p&gt;Here is a dynamic render of the board (that went into prototype production on the 29th of march, 2016).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Plantb0t Rev A" src="/images/plantb0t_RevA_front.png"&gt;&lt;/p&gt;
&lt;p&gt;As you can see it's powered by an ESP-12 and comes with it's own programmer (The lovely CP2102) and micro-USB header. The USB-Port is currently the only way to power the board.&lt;/p&gt;
&lt;p&gt;In the future it is planned to bypass the USB power and only use it for the programmer and otherwise drive everything off an externla powerboard which provides 3.3V for the Plantb0t.&lt;/p&gt;
&lt;p&gt;In the bottom you see two constant current sources that can power two analogue sensors that get multiplexed into the ADC of the ESP-12.&lt;/p&gt;
&lt;p&gt;GPIO pin headers are included for external gismoz such as a pump to act on the moisture data as well as screwholes to mount the whole thing in a 3D printed case.&lt;/p&gt;
&lt;p&gt;In total the board is only 5x5cm big!&lt;/p&gt;
&lt;h1&gt;Future plans&lt;/h1&gt;
&lt;p&gt;A few things I want to realise with this project in the next coming weeks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Primarily the Rev A board needs to be tested to make sure that the programmer works&lt;/li&gt;
&lt;li&gt;Figure out a good way to calibrate the sensors. Maybe drive a button via GPIO?&lt;/li&gt;
&lt;li&gt;Design a power board that generates 3.3V for the board (but not the programmer!) from a solar panel and a battery to decouple the entire sensor-board from all power-sockets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the next revision of the board (Rev B) I want to include more sensor slots. Maybe work on the part spacing a bit and increase footprint sizes. It should be easier to solder and someof the parts are ridiculously small. I mean...I have the whole back to work with?&lt;/p&gt;
&lt;p&gt;I also have some crazy ideas for a "Plantb0t+" Version with even MOAR SENSORS (Including a pH-value sensor!). But that's all faaaaar in the future.&lt;/p&gt;
&lt;p&gt;Either way...I'm excited for my boards to get here (hopefully in the next 7-8 days) as well as all the parts I need for the prototypes.&lt;/p&gt;
&lt;p&gt;I leave you with a screenshot from KiCad where you get to see under the hood of the board. Cheers o/&lt;/p&gt;
&lt;p&gt;&lt;img alt="Plantb0t Rev A" src="/images/plantb0t_RevA_naked.png"&gt;&lt;/p&gt;
&lt;p&gt;(The project has a &lt;a href="https://github.com/spacekookie/open_plantb0t"&gt;Github&lt;/a&gt; repo where I will try to populate the wiki with as much info as possible)&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Wed, 16 Mar 2016 12:08:00 +0100</pubDate><guid>tag:None,2016-03-16:/blog/open-plantbot-rev-a</guid><category>Blog</category><category>/dev/diary</category><category>hardware</category></item><item><title>[Update] Jolly Christmas Decoration</title><link>/blog/update-jolly-christmas-decoration</link><description>&lt;p&gt;You might remember I played around with Kicad a few months ago and made this &lt;a href="/hardware/jolly-christmas-decoration/"&gt;tacky little thing&lt;/a&gt;. Just about 2 1/2 weeks ago I went onto &lt;a href="http://dirtypcbs.com/"&gt;DirtyPCB&lt;/a&gt; to get them actually made. I wanted to have gone through the production process and get something built before I started doing more complicated projects.&lt;/p&gt;
&lt;p&gt;Unfortunately I discovered a little mistake with the design in the layout that ended up at the manufacturer (Rev 3.1). I tried to fix them but Rev 3.2 didn't make it in time, which means my boards will be a bit more complicated to power. However not too complicated as the power-in are just throughholes so I can actually strap anything behind it to power it.&lt;/p&gt;
&lt;p&gt;But without further a due, here is the result from DirtyPCB (which I am actually quite impressed with).&lt;/p&gt;
&lt;p&gt;&lt;img alt="PCB with Banana for Scale" src="/images/christmas_bauble_pcb.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Now, I'm new to all of this so I started doing beep-tests on the pads to make sure things were properly connected and all the boards passed them. The production quality is pretty good. Unfortunately I can't start assembling them yet just because none of the parts I ordered for them have arrived yet. The manufacture and shipping of the boards actually beat the shipping of off-the-shelf parts!&lt;/p&gt;
&lt;p&gt;Anyways, I'm kinda excited. First time making an electronics project. I might post another update on when the parts arive and post a few gifs of the finished products. If I don't I'll probably tweet about it though.&lt;/p&gt;
&lt;p&gt;Now, I have another smaller electronics project in the making where I am, again, waiting for parts to arrive to do some testing. And already designing a modular PCB board. (Limited a bit with the 10x10cm limitations on DirtyPCB I need to design my project in a way that I can take a bunch of smaller panels and stick them together into a large one, which would take hundreds of dollars to make elsewhere).&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=d36wUmJGzvA"&gt;But realistically for the production quality I saw with these, I'd be happy to give them my money again for future projects. Especially at that price, just unbeatable.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;😊&lt;/p&gt;
&lt;p&gt;Anyways, enough ramblings. Read you later.&lt;/p&gt;
&lt;h1&gt;Update...update&lt;/h1&gt;
&lt;p&gt;Right...so after tinkering with the bauble a bit I found out a few things. The most important one being that I made some mistakes. Some big ones :)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pin 9 of the shift register was connected to both input A and input B of the XOR gate. Which meant that both inputs were always the same...which also meant that the output was always 0.&lt;/li&gt;
&lt;li&gt;The 555-timer clock ran at several hundred kilohertz. I had to change the capacitor down to ~12µF and the resistors to ~4.7 ohms.&lt;/li&gt;
&lt;li&gt;The coin-cell battery didn't have enough juice to run it. Two had to be put in parallel. Even then, two batteries would not be able to run for very long.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To make the bauble work I bridget the xor gate completely, so just feeding back the shift register end to the beginning.&lt;/p&gt;
&lt;p&gt;In addition to those things some of the LED's sometimes didn't work. I'm not sure if that is due to broken shift registers, traces or LEDs. All in all I do consider it to have tought me quite a lot about electronics, going through the process of producing a PCB and debugging electronics once it arrived and inevidably goes wrong :)&lt;/p&gt;
&lt;p&gt;I am currently in the process of redesigning the entire circuite from scratch. And making it easier to solder. I want to make it into a beginner soldering kit that people can both learn how to solder with and also have something to hang off their christmas tree in the jolly season. &lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Fri, 27 Nov 2015 15:30:00 +0100</pubDate><guid>tag:None,2015-11-27:/blog/update-jolly-christmas-decoration</guid><category>Blog</category><category>/dev/diary</category><category>hardware</category></item><item><title>Recovering a destroyed LUKs container</title><link>/blog/recovering-a-destroyed-luks-container</link><description>&lt;p&gt;So...funny thing happened to me the other day. And by funny I mean not funny. Actually I mean quite the oposite of funny. I booted my laptop after shutting it shut down for the first time after several weeks of activity and...nothing.&lt;/p&gt;
&lt;p&gt;I stared at my plymouth boot screen while nothing prompted me to type in my passphrase to decrypt my harddrive and the first thought through my mind was:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fuck...I don't have a backup.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;How to debug&lt;/h1&gt;
&lt;p&gt;Now...not to worry, after some time I was dropped into a recovery console where I could ask very simple questions like what kernel modules were present and what Systemd had been up to. And at first I thought the problem was clear: &lt;code&gt;Module failed to load: vboxdrv&lt;/code&gt; and other messages populated my screen – all about VirtualBox kernel modules.&lt;/p&gt;
&lt;p&gt;So the problem was clear. I had fucked up something when installing a new kernel or VirtualBox or anything else. So I blacklisted the modules and moved on...just...that it didn't. The problem persisted. Thinking that I had fucked something up when dealing with the GRUB config or the GRUB recovery console I got my trusty Fedora 22 live-USB out and booted off that.&lt;/p&gt;
&lt;h1&gt;How not to panic&lt;/h1&gt;
&lt;p&gt;Looking at the partitioning on the disk I realised that my 256GB SSD was only 500MB full (which was rightfully detected as an &lt;code&gt;ext4&lt;/code&gt; formatted volume. The rest of my drive was marked as &lt;code&gt;unpartitioned space&lt;/code&gt;. 😱&lt;/p&gt;
&lt;p&gt;Now...here is where things get and got interesting. But first let's have a look at my setup.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sda (the actual drive)
├── sda1 (ext4, mounted as /boot, contains my kernel)
└── sda2 (LUKS Encrypted Volume, contains subvolumes)
   ├── vc-root (RootFS)
   ├── vc-home (HomeFS)
   └── vc-swap (guess c:)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So as you can see my boot drive is outside the LUKS container and unencrypted which was why I even got the chance to enter a recovery console. The rest of my system is encrypted. And seeing that only sda1 was being picked up it meant that the partition table on my disk must have had been destroyed to the point that it no longer knew sda2.&lt;/p&gt;
&lt;p&gt;Knowing this didn't help very much though and it took me a few hours to fix this.&lt;/p&gt;
&lt;h1&gt;Restoring the Partition Table&lt;/h1&gt;
&lt;p&gt;So the main problem was that my partition table was broken. I don't want to start speculating as to why this happened. Maybe my SSD just lost a few blocks, maybe it was bombarded by solar radiation or maybe (just maybe) I was obducted by aliens in the night, refused to give out my master passphrase in my sleep and because of frustration of not being able to get to my data they deleted some junks from my partition table just to spite me.&lt;/p&gt;
&lt;p&gt;Either way, a combination of two applications saved my life and hopefully will save yours.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;testdisk&lt;/code&gt; and &lt;code&gt;cfdisk&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;At first, make sure you have backups ;) And don't blame me if you fuck it up. Also you need to know EXACTLY what your layout is to restore this. Otherwise BAD THINGS WILL HAPPEN &lt;em&gt;waves hand around warning-ly&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;testdisk&lt;/code&gt; on your drive, enter through the screens, let it do a deep search and just say yes to everything it wants to do. This restored the LUKS header for me again at which point my computer at least started seeing the encryption container again. Didn't mean I could log in because keyfiles couldn't be found (they're not in the header apparently).&lt;/p&gt;
&lt;p&gt;After that, I ran &lt;code&gt;cfdisk&lt;/code&gt;. What this program does (or can do) is rebuild your partition table. After letting testdisk have it's go it found my LUKS header and completely destroyed my ext4 bootpartition. So in my case this is what it looked like.
&lt;img alt="cfdisk before it saved us" src="/images/cf_disk1.png" title="cfdisk before"&gt;&lt;/p&gt;
&lt;p&gt;What you will want to do is hit NEW, select the correct size of your partitions. Depending on how running testdisk went for you it might have found different parititions, all of them or none. Please! For the love of god, make sure you get your sectors right. Becase if you don't it will seriously damage your system and might make it completely unusable.
In my caseit was easy, I filled in my boot partition, marked it as bootable and set it's type correctly, also fixed the type error where before sda2 was being picked up as an LVM and not a LUKS container (this is obviously from my running system). And this is what I ended up with.
&lt;img alt=" " src="/images/cf_disk.png" title="cfdisk after"&gt;&lt;/p&gt;
&lt;p&gt;Make sure you write your changes, exit and reboot. And if you did everything right, you will have a working system again.
And that's that. I hope this article will be of use to someone at some point. And remember: make backups!&lt;/p&gt;
&lt;p&gt;Cheers o/&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Thu, 19 Nov 2015 11:41:00 +0100</pubDate><guid>tag:None,2015-11-19:/blog/recovering-a-destroyed-luks-container</guid><category>Blog</category><category>/dev/diary</category><category>data recovery</category><category>linux</category></item><item><title>Jolly Christmas Decoration</title><link>/blog/jolly-christmas-decoration</link><description>&lt;p&gt;Christmas is getting closer (not really but let's just roll with it) and I wanted to learn &lt;a href="www.kicad-pcb.com"&gt;KiCad&lt;/a&gt; a software that let's you create circuits and design PCB for manufacture.&lt;/p&gt;
&lt;p&gt;I found a tutorial series online by a guy named &lt;a href="https://www.youtube.com/channel/UCaBNA-lmg35Wfx2eh2oDkWg"&gt;Ashley Mills&lt;/a&gt; (with quite a legendary beard) who showed off a simple circuit using a 555-timer, a shift register and an XOR gate made from NPN transistors and resistors to display and repeat a pattern on several LED's.&lt;/p&gt;
&lt;p&gt;The series focused on getting to know KiCad and all it's features. And while I did that in the first revision of my board, I've diverged from it since. I can however recommend his videos on KiCad to anyone who wants to dive into PCB design, has no clue about the software and could use a little chuckle while also learning some really awesome software (youtube channel link above).&lt;/p&gt;
&lt;h1&gt;My Christmas Bauble&lt;/h1&gt;
&lt;p&gt;So this is what I've got.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Kookies Christmas Bauble" src="/images/christmas_bauble_pcb.png" title="Kookies Christmas Bauble"&gt;&lt;/p&gt;
&lt;p&gt;As you can see it's a round PCB with simple 5mm LED's around the edges. It no longer uses NPN transistors but rather a single SMD XOR gate. Much easier to wire up, cheaper and less prone to errors as well.&lt;/p&gt;
&lt;p&gt;In general I've switched the entire design over to primarily use SMD components as they're smaller and more elegant. And it theoretically allowed me to get the footprint of the board down to something that isn't too excruciatingly expensive to produce.&lt;/p&gt;
&lt;p&gt;It took me two more revisions to get the board to a state where it's not too complex and actually fit on a single layer (!) with no vias except for the holes for the LED's obviously.&lt;/p&gt;
&lt;p&gt;It uses a round cell battery on the back of the board to hide it away and has a hole at the top to actually hang off a christmas tree. Theoretically the battery should lasta few days, so maybe have a few spare ones around in the christmas season.&lt;/p&gt;
&lt;h1&gt;What now?&lt;/h1&gt;
&lt;p&gt;I haven't manufactured this yet. I am still thinking about refining the design slightly. I have the &lt;strong&gt;entire&lt;/strong&gt; back to work with and add things. I was thinking about adding a simple bluetooth chip so that patterns could be pushed to the device via an android app. But that's the future. For now it should actually be functional and maybe I'll order some &lt;code&gt;Revision 3&lt;/code&gt; boards just to see that everything worked.&lt;/p&gt;
&lt;p&gt;Here is a dynamic render from KiCad as well.
&lt;img alt="Kookies Christmas Bauble Rendered" src="/images/christmas_bauble_render.png" title="Kookies Christmas Bauble Rendered"&gt;&lt;/p&gt;
&lt;p&gt;And be sure to checkout my Github repo for the project if you want the KiCad files. Either to play around with them or to manufacture some baubles yourself. If you do, I'd be interested in pictures of the decorations on your christmas trees so I can add them to this article as a slideshow 😊&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Thu, 17 Sep 2015 15:30:00 +0200</pubDate><guid>tag:None,2015-09-17:/blog/jolly-christmas-decoration</guid><category>Blog</category><category>/dev/diary</category><category>hardware</category></item><item><title>Chaos Communication Camp 2015</title><link>/blog/chaos-communication-camp-2015</link><description>&lt;p&gt;Hey everybody, long time no read.&lt;/p&gt;
&lt;p&gt;As I returned from vacation on the Chaos Communication Camp 2015 (Not sure if I'll post more about that) and probably starting a new job next week (&lt;em&gt;pssst&lt;/em&gt; not sure if I should talk about it 😉 ) the rest of my summer is still ahead of me and I'm booming with ideas and inspiration to do stuff.&lt;/p&gt;
&lt;p&gt;I've started more intensively coding on the &lt;code&gt;newdawn&lt;/code&gt; branch of Reedb, the C port of the database and planning some features for the old codebase via the &lt;code&gt;backports&lt;/code&gt; branch. Because the new codebase will use a different crypto backend (from OpenSSL to gnu_crypt) a migration agent will be neccesary to migrate between 0.11.x to 0.12+ vaults. But as very few people currently use Reedb and most setups are for testing purposes only that isn't a very big priority right now. Depends on how the current version of reedb develops :)&lt;/p&gt;
&lt;p&gt;But that's talk for another day. What else has been going on? After the Chaos Communication Camp 2015 I've been playing around a bit with my rad1o badge.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Rad1o Badge" src="/images/rad1o_badge.png" title="Rad1o Badge"&gt;&lt;/p&gt;
&lt;p&gt;But not much has resulted from that yet. The distribution I'm using (Fedora 22) at this time unfortunately has a broken arm-gcc package which means that a linker for embedded systems isn't working properly. So hacking on that will have to wait a little bit. But I will very likely post more stuff about that in the future.&lt;/p&gt;
&lt;p&gt;Until another day,
Kate&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Katharina Fey</dc:creator><pubDate>Tue, 25 Aug 2015 15:30:00 +0200</pubDate><guid>tag:None,2015-08-25:/blog/chaos-communication-camp-2015</guid><category>Blog</category><category>/dev/diary</category><category>ccc</category><category>c3</category></item></channel></rss>