<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Eric Cheng</title>
    <subtitle>:)</subtitle>
    <link rel="self" type="application/atom+xml" href="https://www.chengeric.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://www.chengeric.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-12-23T00:00:00+00:00</updated>
    <id>https://www.chengeric.com/atom.xml</id>
    <entry xml:lang="en">
        <title>You should use email addresses instead of contact forms</title>
        <published>2025-12-23T00:00:00+00:00</published>
        <updated>2025-12-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/contact-forms/"/>
        <id>https://www.chengeric.com/contact-forms/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/contact-forms/">&lt;p&gt;Contact forms put a buffer between you and the person trying to reach you. Instead of a direct conversation, messages are dropped into a queue whose behavior is often opaque: maybe there’s a confirmation, maybe not; maybe someone reads it, maybe no one does. This distance is sometimes intentional, but people can usually tell. Faced with uncertainty, they either abandon the form or try again somewhere else. And because forms force communication into predefined boxes, they narrow what people say. Context gets shaved off, attachments feel awkward, follow-ups are unclear, and when nothing comes back, it’s hard to tell whether the message was ignored or simply lost.&lt;&#x2F;p&gt;
&lt;p&gt;Email avoids most of these problems by being boring in the right way. It gives both sides a shared record and familiar tools for managing conversations, without extra systems to maintain or fragile pieces that can quietly fail. People can explain themselves fully, attach what matters, loop in others, and see when a conversation has actually ended. If your goal is to hear from people, a visible address and a willingness to answer it is often enough.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Anti-globalism iceberg</title>
        <published>2025-09-28T00:00:00+00:00</published>
        <updated>2025-09-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/domestic/"/>
        <id>https://www.chengeric.com/domestic/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/domestic/">&lt;p&gt;Hiring an H-1B worker? Don’t you support American workers?&lt;&#x2F;p&gt;
&lt;p&gt;Driving a Toyota? Don’t you support American auto companies?&lt;&#x2F;p&gt;
&lt;p&gt;Using an iPhone? Don’t you support American manufacturing?&lt;&#x2F;p&gt;
&lt;p&gt;Eating at a Chinese takeout? Don’t you support American diners?&lt;&#x2F;p&gt;
&lt;p&gt;Drinking coffee? Don’t you support American farmers?&lt;&#x2F;p&gt;
&lt;p&gt;Watching Premier League? Don’t you support American football?&lt;&#x2F;p&gt;
&lt;p&gt;Sipping French wine? Don’t you support Kentucky bourbon?&lt;&#x2F;p&gt;
&lt;p&gt;Practicing yoga? Don’t you support American exercise?&lt;&#x2F;p&gt;
&lt;p&gt;Reading &lt;em&gt;Lord of the Rings&lt;&#x2F;em&gt;? Don’t you support American authors?&lt;&#x2F;p&gt;
&lt;p&gt;Watching anime? Don’t you support American actors?&lt;&#x2F;p&gt;
&lt;p&gt;Listening to k-pop? Don’t you support American artists?&lt;&#x2F;p&gt;
&lt;p&gt;Cooking with olive oil? Don’t you support corn oil?&lt;&#x2F;p&gt;
&lt;p&gt;Using Arabic numerals? Don’t you support Roman numerals?&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Finding the right ethernet jack using the command line</title>
        <published>2025-03-01T00:00:00+00:00</published>
        <updated>2025-03-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/ethernet-test/"/>
        <id>https://www.chengeric.com/ethernet-test/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/ethernet-test/">&lt;p&gt;&lt;strong&gt;The goal:&lt;&#x2F;strong&gt; Identify which ethernet jack in a networking closet’s unlabeled
patch panel corresponds to the ethernet port in your office or bedroom.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The problem:&lt;&#x2F;strong&gt; You’re blindly plugging your cable into different jacks,
relying on either the router’s blinking lights or repeatedly walking back to
your laptop to check for a network connection.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The solution:&lt;&#x2F;strong&gt; Run the following command in your MacBook’s&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; terminal. It
will continuously check for an internet connection and audibly announce its
status, allowing you to test jacks without needing to walk back and forth. When
you hear “&lt;em&gt;connected&lt;&#x2F;em&gt;” from the other room, you’ve found the right port!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span&gt;true&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;; do &lt;&#x2F;span&gt;&lt;span&gt;ping -c1 -t1 1.1.1.1 &amp;gt;&#x2F;dev&#x2F;null &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;say &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Connected&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|| &lt;&#x2F;span&gt;&lt;span&gt;say &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Disconnected&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span&gt;sleep 0.5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;; done
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Linux users would need to replace &lt;code&gt;say&lt;&#x2F;code&gt; with something like
&lt;code&gt;speech-dispatcher&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Reflections on Why Nations Fail</title>
        <published>2024-10-16T00:00:00+00:00</published>
        <updated>2024-10-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/whynationsfail/"/>
        <id>https://www.chengeric.com/whynationsfail/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/whynationsfail/">&lt;p&gt;I started reading &lt;em&gt;Why Nations Fail&lt;&#x2F;em&gt; at the beginning of the year when I
replaced my 10-year old Kindle. I wish they still made these things with a
BlackBerry-style keyboard.&lt;&#x2F;p&gt;
&lt;p&gt;Anyways, I really enjoyed this book. It’s incredibly interesting with its huge
gallery of historical examples while remaining approachable to economics
dilettantes. The authors articulate a very powerful claim about global
development that I have felt innately for a long time but been unable to argue
nearly as precisely. Simply put, the book argues that societies that provide
inclusive political and economic institutions—allowing broad participation,
rights, and shared prosperity—are more likely to succeed, while those with
extractive institutions, which concentrate power and wealth in the hands of a
few, are prone to stagnation and failure.&lt;&#x2F;p&gt;
&lt;p&gt;The book goes into detail explaining how this theory is evident in various
societies throughout history, while also swatting down other popular
explanations for why some countries are wealthy and others are not—such as
differences in climate, culture, or resources.&lt;&#x2F;p&gt;
&lt;p&gt;I’m writing this about a week after the authors Daron Acemoglu and James
Robinson won the economics Nobel prize&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#nobel&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; this year with collaborator Simon
Johnson. I’ve seen criticism levied at the book’s supposed tunnel vision on
solely attributing societal success or failure to the inclusiveness of its
institutions, as well as the claim that the book ignores the effects of
colonialism in helping Western countries achieve their modern day wealth.&lt;&#x2F;p&gt;
&lt;p&gt;I disagree with these these points.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#annoying&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; There is ample evidence to
suggest that the long-run path of countries with similar starting
conditions—similar geography, similar availability of resources, similar
history of past colonization—end up with vastly different societal outcomes
depending on their institutions. For instance, compare South and North Korea,
former West and East Germany, Poland and Belarus, Taiwan and China, Finland and
Russia, Israel and Syria, or Botswana and Zimbabwe.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;China in particular is a funny case, because critics claim that it was able to
rapidly develop into an economic superpower while remaining a single-party
Communist state, thus invalidating the claim that liberal democracies are a
necessary condition for sustainable economic growth. The ironic point,
however, is that China achieved this rapid growth &lt;em&gt;because&lt;&#x2F;em&gt; it adopted liberal
economic practices in the 1980’s which made it easier for foreign investors
and domestic companies to start doing business. If China were to, you know,
fully liberalize its economy and democratize then one can realistically
imagine they would already be the dominant economic and cultural superpower on
the planet.&lt;&#x2F;p&gt;
&lt;p&gt;To this point, we are currently witnessing China becoming more autocratic. As
both the book and reality have repeatedly shown, such political systems
eventually tend to drift towards stupid political side quests which sabotage
economic development. And as we have seen post-pandemic, this self-inflicted
kneecapping has only begun.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;In any case, I am happy to see that there is renewed interest in this book after
the announcement of this year’s Nobel recipient and the larger political
economic theory behind it. Backtesting such a grand theory on the world, as the
book does, is one thing, and being able to predict the future is another. I’ll
revisit this post in 2074 to see if its legacy held up.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;nobel&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Yes I know it’s technically not a Nobel prize&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;annoying&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;On a related note, I find it frustrating when concepts such as democracy,
liberalism, or capitalism are described as uniquely Western and therefore
only compatible in Western societies. Both proponents &lt;em&gt;and&lt;&#x2F;em&gt; critics of these
values sometimes are guilty of this. Like dude, relax, you can’t patent an
ideology.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ChatGPT is the McDonald&#x27;s of English</title>
        <published>2024-06-23T00:00:00+00:00</published>
        <updated>2024-06-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/chatgpt/"/>
        <id>https://www.chengeric.com/chatgpt/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/chatgpt/">&lt;p&gt;In theory, you could use ChatGPT to become a better writer. But this is just as realistic as going to
McDonald’s to order a salad.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; It just doesn’t work like that; both of these things
encourage you to become lazy and are unhealthy for you.&lt;&#x2F;p&gt;
&lt;p&gt;If you’re unwilling to be creative and use ChatGPT to write formal emails, one
pagers, performance reviews, or other important documents, you weaken your
imagination and reasoning skills. Writing isn’t the result of thinking; it &lt;em&gt;is&lt;&#x2F;em&gt;
thinking. When you delegate your writing to ChatGPT, who does the thinking?&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Writing well exercises your ability to do two things: thinking to completion and
thinking with concision. You need to infiltrate your own argument to discover
any logical gaps. Then you should find the least amount of words necessary to
express your argument.&lt;&#x2F;p&gt;
&lt;p&gt;ChatGPT, especially its free-to-use version, often fails to achieve either. For
instance, if you ask it to write something substantial around a few sparse
bullet points, it leans too heavily on your prompt. If your premise was flawed
or contained mistakes, so will ChatGPT’s output. And since people prompt ChatGPT
with awful instructions such as
&lt;code&gt;&quot;rewrite this into super detailed professional tone,&quot;&lt;&#x2F;code&gt; you’ll get verbose, fast
food-style English.&lt;&#x2F;p&gt;
&lt;p&gt;This boring behavior is apparent by design, since ChatGPT is running a model
that just infers its next word by calculating what came before and selecting the
most probable result. It dulls any unique writing to sound like the training
data it inherited.&lt;&#x2F;p&gt;
&lt;p&gt;ChatGPT is quite good at tasks which involve reducing content, such as
summarization. But if you’re looking to create something new and wish to become
a better writer, then you should avoid using ChatGPT to do the hard work for
you. It does not merely make you sound unoriginal (&lt;em&gt;“let’s delve into this
topic”&lt;&#x2F;em&gt;, &lt;em&gt;“this underscores the importance of…”&lt;&#x2F;em&gt;, &lt;em&gt;“I hope this email finds
you well”&lt;&#x2F;em&gt;), it actually makes you unoriginal.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yobibyte.github.io&#x2F;notebooks.html&quot;&gt;notebooks are McDonalds of
code&lt;&#x2F;a&gt; by Vitaly Kurin (@yobibyte)&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Quick sidenote: ChatGPT is not the only tool guilty of inhibiting writing.
For instance, PowerPoint has a knack for letting people
disguise bad writing with bullet points, with the bullet points themselves
disguising the bad thinking beneath.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Reflections on the xz backdoor</title>
        <published>2024-04-02T00:00:00+00:00</published>
        <updated>2024-04-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/xz-backdoor/"/>
        <id>https://www.chengeric.com/xz-backdoor/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/xz-backdoor/">&lt;blockquote&gt;
&lt;p&gt;The actual bug I planted in the compiler would match code in the UNIX “login”
command. The placement code would miscompile the login command so that it
would accept either the intended encrypted password or a particular known
password. Thus if this code were installed in binary and the binary were used
to compile the login command, I could log into that system as any user.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.cs.cmu.edu&#x2F;~rdriley&#x2F;487&#x2F;papers&#x2F;Thompson_1984_ReflectionsonTrustingTrust.pdf&quot;&gt;- Ken Thompson, &lt;em&gt;Reflections on Trusting Trust&lt;&#x2F;em&gt;
(1984)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The xz backdoor is the hottest CVE of the decade. &lt;a href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;xz-timeline&quot;&gt;There were so many crazy
social engineering and technical tricks that are frankly above my level to try
and explain them all.&lt;&#x2F;a&gt; The attacker was
clearly skilled as evidenced by their work: creeping updates that modified the
&lt;a href=&quot;https:&#x2F;&#x2F;git.tukaani.org&#x2F;?p=xz.git;a=commitdiff;h=328c52da8a2bbb81307644efdb58db2c422d9ba7&quot;&gt;test
system&lt;&#x2F;a&gt;
and build scripts gradually, concealing a payload within binary data for
seemingly innocuous test cases, developing an activation system that was &lt;a href=&quot;https:&#x2F;&#x2F;gynvael.coldwind.pl&#x2F;?lang=en&amp;amp;id=782&quot;&gt;robust
enough to future-proof the
backdoor&lt;&#x2F;a&gt;. But the attacker was
still not careful enough to prevent a performance regression from affecting
sshd, and Andres Freund was curious enough to chase down 500 milliseconds of
latency.&lt;&#x2F;p&gt;
&lt;p&gt;We were lucky Freund dove down this rabbit hole and emerged with the stunning
discovery of a major vulnerability so quickly. But this discovery of the xz
backdoor was by no means assured. Open source allows everybody to view code, it
doesn’t guarantee that anybody actually does. In this specific instance, the xz
backdoor wasn’t even present in the code itself. It took a very clever inference
to connect a sshd slowdown with some seemingly unrelated Valgrind complaints to
catch onto the beginning of something sinister going on in xz. To be technically
shrewd enough to understand this, care enough to investigate, and willing to
share with others is a rare combination limited to a tiny portion of the
open-source community. Yes, open-source triumphed this time, but what about the
next time?&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Open source development is currently a high-trust environment, and I fear that
suspicion about this case is going to color all sorts of future interactions.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;bentsukun.ch&#x2F;posts&#x2F;xz-backdoor&#x2F;&quot;&gt;- Benny Siegert, &lt;em&gt;The XZ Backdoor&lt;&#x2F;em&gt;
(2024)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Siegert mentions that NetBSD requires that a new contributor must have their PGP
key signed by an existing NetBSD developer at an-inperson meetup. However, the
challenge lies in the fact that tail-end supply chain attacks are highly patient
and sophisticated. In this particular attack, Jia Tan and the other sock-puppet
accounts lacked any online history or record.
But there is widespread suspicion that these various accounts were pseudonyms used by a group of
malicious actors backed by a nation-state. If this is indeed true, it is likely
that a well-prepared attacker in the future will find ways to adopt, fabricate,
or compromise a credible identity. Requiring that developers use real identities
would deter some attackers, but not the most determined.&lt;&#x2F;p&gt;
&lt;p&gt;Moreover, the average open source project probably only has a single
contributor. Few projects, such as the Linux kernel, have the security qualities
that a large number of competent hackers can provide when scrutinizing code that
gets merged. If the &lt;a href=&quot;https:&#x2F;&#x2F;qz.com&#x2F;646467&#x2F;how-one-programmer-broke-the-internet-by-deleting-a-tiny-piece-of-code&quot;&gt;original software author sabotages their own
code&lt;&#x2F;a&gt;,
then we are left with few solutions.&lt;&#x2F;p&gt;
&lt;p&gt;There is no straightforward solution to these issues because they stems from a
lack of trust rather than a technical flaw. Microsoft or Google could some day
develop some AI product that scans open source GitHub repositories for malicious
code, but these will ultimately be mere warning signs and not permanent
remedies.&lt;&#x2F;p&gt;
&lt;p&gt;Regardless of whether you consider it within the domains of software
development, banking, or the law: trust is an unsolved problem. This recent xz
backdoor is a reminder of that.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Using NixOS for my homelab</title>
        <published>2024-03-23T00:00:00+00:00</published>
        <updated>2024-03-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/homelab/"/>
        <id>https://www.chengeric.com/homelab/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/homelab/">
































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;servers.990b032dcd0647e0.jpg&quot;
        class=&quot;&quot; alt=&quot;servers&quot;  width=677 &#x2F;&gt;
    &lt;figcaption&gt;3x
M710q ThinkCenter Tiny&#x27;s equipped with an Intel i5-7500T, 8GB RAM, 256GB NVMe
and 5TB HDD&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;br&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Post updated on December 03, 2025.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;&#x2F;strong&gt; You can find my Nix config repository
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;eh8&#x2F;chenglab&quot;&gt;here&lt;&#x2F;a&gt;, or skip to the &lt;a href=&quot;https:&#x2F;&#x2F;www.chengeric.com&#x2F;homelab&#x2F;#installing-nixos-on-bare-metal-servers&quot;&gt;actual installation
writeup&lt;&#x2F;a&gt;. I encourage you to see
how I tackled different problems and to reuse any code you find useful. I now
publish a ready-made ISO and WSL tarball in the GitHub release page to make it
even easier to poke around. &lt;a href=&quot;mailto:nixos@chengeric.com&quot;&gt;Reach out&lt;&#x2F;a&gt; if you have
any questions!&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;a class=&quot;zola-anchor&quot; href=&quot;#motivation&quot; aria-label=&quot;Anchor link for: motivation&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In a way, this blog post has effectively taken four years to write. I originally
became interested in self-hosting and home servers when the pandemic took hold,
and then used every mainstream Linux distribution and configuration management
system until I came across NixOS, which incredibly triumphs at being both.&lt;&#x2F;p&gt;
&lt;p&gt;Two years ago, I was already fairly experienced with problem solving in Arch
Linux. I used Arch on every laptop, desktop, and server I owned. But I still
felt uneasy about the fragility of my setup and the likelihood of forgetting how
to configure something again if anything were to break. I had the choice of
either finishing my Ansible configuration or commit to learning something new.
Eventually I became frustrated with the excessive boilerplating and slowness of
Ansible. It was time to take the dive into NixOS.&lt;&#x2F;p&gt;
&lt;p&gt;I actually failed to enter the Nix ecosystem twice, first in 2022 and then later
in 2023. Functional programming was too alien for me, and I persuaded myself
that NixOS was too gimmicky and non-transferable as a skillset. But the allure
of declarative management was too promising to ignore. I decided to try once
more at the end of 2023.&lt;&#x2F;p&gt;
&lt;p&gt;This time, I did it! I now configure my M1 MacBook Air, an AMD Ryzen desktop
computer, a Windows Subsystem for Linux environment for work, and several
ThinkCenter Tiny servers using a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;eh8&#x2F;chenglab&quot;&gt;single
repository&lt;&#x2F;a&gt;. Everything from my dotfiles to my
Nextcloud installation config is organized together, which would have been
nearly impossible otherwise.&lt;&#x2F;p&gt;
&lt;p&gt;Learning NixOS this time around was easier partially because of the steadily
increasing availability of high-quality blog posts, videos, and other
documentation resources. The reputation of Nix being too clever for its own good
is arguably exaggerated and improves everyday as layman-friendly documentation
catches up. Furthermore, the proliferation of Nix flakes means more
configurations are being shared publicly.&lt;&#x2F;p&gt;
&lt;p&gt;But I ultimately prevailed because I was much more realistic about starting from
the most minimal, barebones configuration I could find on GitHub. From there, I
incrementally added complexity without smashing into a brick wall of unfamiliar
syntax and stack traces. As long as I didn’t frustrate myself trying to
immediately emulate an experienced user’s seemingly overengineered config
repository, I could trust my sense of curiosity to provide the necessary
endurance to push through.&lt;&#x2F;p&gt;
&lt;p&gt;So why go through the trouble of migrating my servers to NixOS?&lt;&#x2F;p&gt;
&lt;p&gt;The obvious benefits of NixOS were known before I started using Nix:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Your &lt;strong&gt;entire&lt;&#x2F;strong&gt; operating system points to a &lt;strong&gt;single source of truth&lt;&#x2F;strong&gt;
embodied in your NixOS configuration. No more guessing where to find and place
various program configuration files. No more wondering why something doesn’t
run on your machine and trying to figure out what the workaround is.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Thanks to its declarative design, NixOS lets you abstract large chunks of
complexity away from system administration. Want to enable &lt;a href=&quot;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;title&#x2F;Zram&quot;&gt;some OS
feature&lt;&#x2F;a&gt; that would have taken multiple
imperative steps to complete? &lt;a href=&quot;https:&#x2F;&#x2F;search.nixos.org&#x2F;options?channel=25.11&amp;amp;show=zramSwap.enable&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=zram&quot;&gt;No
problem&lt;&#x2F;a&gt;.
If Ansible is designed to make your grocery shopping and cooking easier, NixOS
just lets you order your food directly.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Unlike Ansible, which achieves idempotency through implementation, NixOS
achieves it by design. You can be certain that a given Nix configuration on
machine can and will reliably produce the same output on another, i.e.
deterministic builds and reproducible deployments.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;NixOS is fast: I can provision a new {file,media,home automation} server from
scratch in roughly 10 minutes from the installer ISO.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;There are other configuration management &amp;amp; system orchestration tools out
there that I haven’t mentioned, but nearly every imperative process has the same
overall pitfalls. As a practical example, take setting up Nextcloud on a bare
metal Arch Linux server. This is &lt;a href=&quot;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;title&#x2F;Nextcloud&quot;&gt;a super involved and tedious
process&lt;&#x2F;a&gt;. Even the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nextcloud&#x2F;all-in-one&#x2F;blob&#x2F;main&#x2F;manual-install&#x2F;latest.yml&quot;&gt;official
all-in-one Nextcloud &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt;
file&lt;&#x2F;a&gt;
takes some serious time to inspect through and understand. Meanwhile, a
comparable Nix configuration that sets up Nextcloud along with a reverse proxy,
automated off-site backups, and Redis caching is much easier to write and
maintain. Here’s &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;eh8&#x2F;chenglab&#x2F;blob&#x2F;main&#x2F;services&#x2F;nextcloud.nix&quot;&gt;mine for
comparison&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;But it is the not-so-obvious benefits keep me interested. Nix flakes, as I would
later discover, make it possible to share code with other Nix users universally.
It’s like a &lt;code&gt;package.json&lt;&#x2F;code&gt;, but for your operating system and developer
environment. This enables you to add useful add-on functionality to your system
at almost no marginal complexity. For instance, I use
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Mic92&#x2F;sops-nix&quot;&gt;sops-nix&lt;&#x2F;a&gt; to manage my secrets and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;home-manager&quot;&gt;Home
Manager&lt;&#x2F;a&gt; to manage my dotfiles by
declaring them as dependencies in my &lt;code&gt;flake.nix&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;p&gt;You can even run programs, such as a linter, directly from your command line
without actually having installed anything first.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span&gt;nix run &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;git+https:&#x2F;&#x2F;git.peppe.rs&#x2F;languages&#x2F;statix&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;-- --&lt;&#x2F;span&gt;&lt;span&gt;help
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;NixOS also lets you easily achieve some very unorthodox system configurations.
You can run your computer on tmpfs, since NixOS only needs &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;nix&lt;&#x2F;code&gt; to
boot up and rebuild your entire system configuration from scratch everytime your
computer turns on. Everything can be tracked in your VCS, and you’ll easily know
the entire surface area of your device with great precision.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#impermanence&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you found this post interesting and you’re ready to take the leap into NixOS,
feel free to check out &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;eh8&#x2F;chenglab&quot;&gt;my repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installing-nixos-on-bare-metal-servers&quot;&gt;Installing NixOS on bare metal servers&lt;a class=&quot;zola-anchor&quot; href=&quot;#installing-nixos-on-bare-metal-servers&quot; aria-label=&quot;Anchor link for: installing-nixos-on-bare-metal-servers&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Okay, here comes the fun part! I’ll walk you through how I install NixOS on the
three servers pictured above.&lt;&#x2F;p&gt;
&lt;p&gt;My goal with the three servers was the following setup:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;svr1chng&lt;&#x2F;th&gt;&lt;th&gt;svr2chng&lt;&#x2F;th&gt;&lt;th&gt;svr3chng&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Primary app&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Nextcloud&lt;&#x2F;td&gt;&lt;td&gt;Homebridge, Scrypted&lt;&#x2F;td&gt;&lt;td&gt;Jellyfin&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Remote access&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Tailscale&lt;&#x2F;td&gt;&lt;td&gt;Tailscale&lt;&#x2F;td&gt;&lt;td&gt;Tailscale&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Internet access&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;–&lt;&#x2F;td&gt;&lt;td&gt;–&lt;&#x2F;td&gt;&lt;td&gt;Cloudflared Tunnel&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Security&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Full disk encryption&lt;&#x2F;td&gt;&lt;td&gt;Full disk encryption&lt;&#x2F;td&gt;&lt;td&gt;Full disk encryption&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Disk setup&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;256GB NVMe, 5TB HDD&lt;&#x2F;td&gt;&lt;td&gt;256GB NVMe, 5TB HDD&lt;&#x2F;td&gt;&lt;td&gt;256GB NVMe, 5TB HDD&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;creating-a-custom-iso&quot;&gt;Creating a custom ISO&lt;a class=&quot;zola-anchor&quot; href=&quot;#creating-a-custom-iso&quot; aria-label=&quot;Anchor link for: creating-a-custom-iso&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Since I velcroed my server’s power cables in quite an unconvenient way, I
couldn’t be bothered to plug them into a monitor and keyboard for the
installation.&lt;&#x2F;p&gt;
&lt;p&gt;Luckily, NixOS makes it very easy to generate a custom ISO with
your SSH public key so you can handle installation remotely. I now keep
the ISO definition inside my flake so I can build a headless installer that is
already baked with my SSH public key and a friendly MOTD that links to my
install script.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# machines&#x2F;iso1chng&#x2F;configuration.nix
&lt;&#x2F;span&gt;&lt;span&gt;{vars&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;, ...&lt;&#x2F;span&gt;&lt;span&gt;}: {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;imports &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;..&#x2F;..&#x2F;modules&#x2F;nixos&#x2F;iso.nix&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  ];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;hostName &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;iso1chng&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# modules&#x2F;nixos&#x2F;iso.nix
&lt;&#x2F;span&gt;&lt;span&gt;{vars&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;, ...&lt;&#x2F;span&gt;&lt;span&gt;}: {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;imports &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;_packages.nix&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  ];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixos &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;isNormalUser &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;extraGroups &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;wheel&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;openssh&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;authorizedKeys&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;keys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;      vars&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;sshPublicKeyPersonal
&lt;&#x2F;span&gt;&lt;span&gt;    ];
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;motd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;    Welcome to the Chenglab ISO installer!
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;    To install the system, copy and paste the following command:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;    sudo bash -c &amp;quot;$(curl -fsSL https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;eh8&#x2F;chenglab&#x2F;main&#x2F;install.sh)&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;  &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;security&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;wheelNeedsPassword &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= false&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;allowUnfree &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nix&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;settings&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;experimental-features &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nix-command&amp;quot; &amp;quot;flakes&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;openssh&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;stateVersion &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;23.11&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now all it takes to produce a new ISO is:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;$ nix build .#nixosConfigurations.iso1chng.config.system.build.isoImage
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The ISO lands in &lt;code&gt;result&#x2F;&lt;&#x2F;code&gt;.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#iso&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; I also publish a prebuilt one in the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;eh8&#x2F;chenglab&#x2F;releases&#x2F;&quot;&gt;GitHub
release page&lt;&#x2F;a&gt; as &lt;code&gt;nixos.iso&lt;&#x2F;code&gt; (alongside &lt;code&gt;nixos.wsl&lt;&#x2F;code&gt;) so I can skip the build step
entirely.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;remotely-entering-nixos-installer&quot;&gt;Remotely entering NixOS installer&lt;a class=&quot;zola-anchor&quot; href=&quot;#remotely-entering-nixos-installer&quot; aria-label=&quot;Anchor link for: remotely-entering-nixos-installer&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I use &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ventoy&#x2F;Ventoy&quot;&gt;Ventoy&lt;&#x2F;a&gt; on a flash drive to store
multiple ISO files on the same bootable USB drive. This is super convenient for
using a single USB drive for installing multiple OSes. My flash drive has the
following structure:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;.
&lt;&#x2F;span&gt;&lt;span&gt;├── ISO
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── Win11_24H2_English_x64.iso
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── archlinux-2025.10.01-x86_64.iso
&lt;&#x2F;span&gt;&lt;span&gt;│   └── nixos.iso
&lt;&#x2F;span&gt;&lt;span&gt;└── ventoy
&lt;&#x2F;span&gt;&lt;span&gt;    └── ventoy.json
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice how I created &lt;code&gt;ventoy&#x2F;ventoy.json&lt;&#x2F;code&gt; to automatically load the newly
generated NixOS ISO:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;control&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;VTOY_DEFAULT_SEARCH_ROOT&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;ISO&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;VTOY_MENU_TIMEOUT&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;5&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;VTOY_DEFAULT_IMAGE&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;ISO&#x2F;nixos.iso&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;VTOY_SECONDARY_BOOT_MENU&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;1&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;VTOY_SECONDARY_TIMEOUT&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;5&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  ]
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The release workflow always names the artifacts &lt;code&gt;nixos.iso&lt;&#x2F;code&gt; and &lt;code&gt;nixos.wsl&lt;&#x2F;code&gt;, so
keeping the default image pointed at &lt;code&gt;nixos.iso&lt;&#x2F;code&gt; saves me from having to tweak
this file after each release.&lt;&#x2F;p&gt;
&lt;p&gt;I plugged my USB drive into the first server and rebooted it. After SSH’ing in,
I was greeted not by my familiar Arch Linux environment, but rather the NixOS
installer ISO. Nice!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;running-my-nixos-install-script&quot;&gt;Running my NixOS install script&lt;a class=&quot;zola-anchor&quot; href=&quot;#running-my-nixos-install-script&quot; aria-label=&quot;Anchor link for: running-my-nixos-install-script&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I created an install script that now handles macOS prerequisites as well as the
Linux flow. The Linux path still partitions the NVMe drive that would serve as
the main filesystem for the server, sets up full disk encryption and prompts me
for a password, mounts the new partitions, and generates a new age public key
that I use with &lt;code&gt;sops-nix&lt;&#x2F;code&gt;. Here is an excerpt of it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env bash
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;set -e -u -o pipefail
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Define disk
&lt;&#x2F;span&gt;&lt;span&gt;DISK=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;nvme0n1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;DISK_BOOT_PARTITION=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;nvme0n1p1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;DISK_NIX_PARTITION=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;nvme0n1p2&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Undo any previous changes if applicable
&lt;&#x2F;span&gt;&lt;span&gt;set +e
&lt;&#x2F;span&gt;&lt;span&gt;umount -R &#x2F;mnt
&lt;&#x2F;span&gt;&lt;span&gt;cryptsetup close cryptroot
&lt;&#x2F;span&gt;&lt;span&gt;set -e
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Partitioning disk
&lt;&#x2F;span&gt;&lt;span&gt;parted $DISK&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt; --&lt;&#x2F;span&gt;&lt;span&gt; mklabel gpt
&lt;&#x2F;span&gt;&lt;span&gt;parted $DISK&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt; --&lt;&#x2F;span&gt;&lt;span&gt; mkpart ESP fat32 1MiB 512MiB
&lt;&#x2F;span&gt;&lt;span&gt;parted $DISK&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt; --&lt;&#x2F;span&gt;&lt;span&gt; set 1 boot on
&lt;&#x2F;span&gt;&lt;span&gt;parted $DISK&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt; --&lt;&#x2F;span&gt;&lt;span&gt; mkpart Nix 512MiB 100%
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Setting up encryption
&lt;&#x2F;span&gt;&lt;span&gt;cryptsetup -q -v luksFormat $DISK_NIX_PARTITION
&lt;&#x2F;span&gt;&lt;span&gt;cryptsetup -q -v open $DISK_NIX_PARTITION cryptroot
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Creating filesystems
&lt;&#x2F;span&gt;&lt;span&gt;mkfs.fat -F32 -n boot $DISK_BOOT_PARTITION
&lt;&#x2F;span&gt;&lt;span&gt;mkfs.ext4 -F -L nix -m 0 &#x2F;dev&#x2F;mapper&#x2F;cryptroot
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Let mkfs catch its breath
&lt;&#x2F;span&gt;&lt;span&gt;sleep 2
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Mounting filesystems
&lt;&#x2F;span&gt;&lt;span&gt;mount -t tmpfs none &#x2F;mnt
&lt;&#x2F;span&gt;&lt;span&gt;mkdir -pv &#x2F;mnt&#x2F;{boot,nix,etc&#x2F;ssh,var&#x2F;{lib,log}}
&lt;&#x2F;span&gt;&lt;span&gt;mount &#x2F;dev&#x2F;disk&#x2F;by-label&#x2F;boot &#x2F;mnt&#x2F;boot
&lt;&#x2F;span&gt;&lt;span&gt;mount &#x2F;dev&#x2F;disk&#x2F;by-label&#x2F;nix &#x2F;mnt&#x2F;nix
&lt;&#x2F;span&gt;&lt;span&gt;mkdir -pv &#x2F;mnt&#x2F;nix&#x2F;{secret&#x2F;initrd,persist&#x2F;{etc&#x2F;ssh,var&#x2F;{lib,log}}}
&lt;&#x2F;span&gt;&lt;span&gt;chmod 0700 &#x2F;mnt&#x2F;nix&#x2F;secret
&lt;&#x2F;span&gt;&lt;span&gt;mount -o bind &#x2F;mnt&#x2F;nix&#x2F;persist&#x2F;var&#x2F;log &#x2F;mnt&#x2F;var&#x2F;log
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Generating initrd SSH host key
&lt;&#x2F;span&gt;&lt;span&gt;ssh-keygen -t ed25519 -N &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; -C &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; -f &#x2F;mnt&#x2F;nix&#x2F;secret&#x2F;initrd&#x2F;ssh_host_ed25519_key
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Creating public age key for sops-nix
&lt;&#x2F;span&gt;&lt;span&gt;sudo nix-shell --extra-experimental-features flakes -p ssh-to-age --run &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;cat &#x2F;mnt&#x2F;nix&#x2F;secret&#x2F;initrd&#x2F;ssh_host_ed25519_key.pub | ssh-to-age&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I took the resulting generated public key and added it to the &lt;code&gt;.sops.yaml&lt;&#x2F;code&gt; file
at the root of my repository. After synchronizing the new keys by running &lt;code&gt;for file in secrets&#x2F;*; do sops updatekeys &quot;$file&quot;; done&lt;&#x2F;code&gt; and committing these
changes to GitHub, I was ready to install NixOS on the new server.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;drawing-the-rest-of-the-owl&quot;&gt;Drawing the rest of the owl&lt;a class=&quot;zola-anchor&quot; href=&quot;#drawing-the-rest-of-the-owl&quot; aria-label=&quot;Anchor link for: drawing-the-rest-of-the-owl&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I could control what type of setup I wanted to install by adjusting the hostname
parameter at the end of my flake install command to &lt;code&gt;svr1chng&lt;&#x2F;code&gt;, &lt;code&gt;svr2chng&lt;&#x2F;code&gt;, or
&lt;code&gt;svr3chng&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;$ sudo nixos-install --no-root-passwd --root &#x2F;mnt --flake github:eh8&#x2F;chenglab#hostname
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After a few minutes, the installation process was completed with no issues and I
could reboot the server without the USB drive.&lt;&#x2F;p&gt;
&lt;p&gt;The server spawned an SSH daemon on boot to receive the LUKS decryption key. To
unlock the server, I logged into the &lt;code&gt;root&lt;&#x2F;code&gt; account for the designated IP
address:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;$ ssh root@&amp;lt;SERVER IP&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;Last login: Sun Mar 24 05:24:28 2024 from 10.0.0.1
&lt;&#x2F;span&gt;&lt;span&gt;Passphrase for &#x2F;dev&#x2F;nvme0n1p2:
&lt;&#x2F;span&gt;&lt;span&gt;Waiting 10 seconds for LUKS to request a passphrase........Connection to &amp;lt;SERVER IP&amp;gt; closed by remote host.
&lt;&#x2F;span&gt;&lt;span&gt;Connection to &amp;lt;SERVER IP&amp;gt; closed.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The server then proceeded with the bootup sequence normally. Using Tailscale, I
logged into my server to a complete, freshly provisioned server.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#tailscale&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;$ ssh svr1chng
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# tada!
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;anatomy-of-my-configuration&quot;&gt;Anatomy of my configuration&lt;a class=&quot;zola-anchor&quot; href=&quot;#anatomy-of-my-configuration&quot; aria-label=&quot;Anchor link for: anatomy-of-my-configuration&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;modular-configuration&quot;&gt;Modular configuration&lt;a class=&quot;zola-anchor&quot; href=&quot;#modular-configuration&quot; aria-label=&quot;Anchor link for: modular-configuration&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I began by using taking the &lt;em&gt;minimal&lt;&#x2F;em&gt; example from a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Misterio77&#x2F;nix-starter-configs&quot;&gt;GitHub repository
conveniently named &lt;code&gt;nix-starter-configs&lt;&#x2F;code&gt; by
Misterio77&lt;&#x2F;a&gt;.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#starter&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; The
standard example was too confusing for me at first.&lt;&#x2F;p&gt;
&lt;p&gt;The repo has grown since then, so I now keep a couple helper functions in
&lt;code&gt;flake.nix&lt;&#x2F;code&gt; to avoid repeating the same boilerplate for NixOS, nix-darwin, WSL,
and the custom ISO target. The shared &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;eh8&#x2F;chenglab&#x2F;blob&#x2F;main&#x2F;vars.nix&quot;&gt;&lt;code&gt;vars.nix&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; keeps usernames, keys, and
emails in one place.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;description &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;chenglab&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;inputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:nixos&#x2F;nixpkgs&#x2F;nixos-25.11&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixpkgs-unstable&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:nixos&#x2F;nixpkgs&#x2F;nixos-unstable&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;impermanence&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:nix-community&#x2F;impermanence&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;home-manager &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:nix-community&#x2F;home-manager&#x2F;release-25.11&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nix-darwin &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:nix-darwin&#x2F;nix-darwin&#x2F;nix-darwin-25.11&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;sops-nix &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:Mic92&#x2F;sops-nix&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixarr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:rasmus-kirk&#x2F;nixarr&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nix-homebrew &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:zhaofengli-wip&#x2F;nix-homebrew&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;homebrew-bundle &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:homebrew&#x2F;homebrew-bundle&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;flake &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= false&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;homebrew-core &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:homebrew&#x2F;homebrew-core&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;flake &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= false&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;homebrew-cask &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:homebrew&#x2F;homebrew-cask&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;flake &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= false&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixos-wsl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:nix-community&#x2F;NixOS-WSL&#x2F;main&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;vscode-server &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:nix-community&#x2F;nixos-vscode-server&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;inputs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;follows &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nixpkgs&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;outputs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    nix-darwin&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span&gt;} @ inputs: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;let
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span&gt;(self) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;outputs&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;vars &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;vars.nix&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;systems &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;x86_64-linux&amp;quot; &amp;quot;aarch64-darwin&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;forAllSystems &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;genAttrs systems;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;mkNixOSConfig &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;path:
&lt;&#x2F;span&gt;&lt;span&gt;      nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;nixosSystem {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;specialArgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;inputs outputs vars&lt;&#x2F;span&gt;&lt;span&gt;;};
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;modules &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[path];
&lt;&#x2F;span&gt;&lt;span&gt;      };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;mkDarwinConfig &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;path:
&lt;&#x2F;span&gt;&lt;span&gt;      nix-darwin&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;darwinSystem {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;specialArgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;inputs outputs vars&lt;&#x2F;span&gt;&lt;span&gt;;};
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;modules &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[path];
&lt;&#x2F;span&gt;&lt;span&gt;      };
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;formatter &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;forAllSystems (system: nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;legacyPackages&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;${system}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;alejandra);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;darwinConfigurations &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;mac1chng &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;mkDarwinConfig &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;machines&#x2F;mac1chng&#x2F;configuration.nix&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixosConfigurations &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;workchng &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;mkNixOSConfig &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;machines&#x2F;workchng&#x2F;configuration.nix&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;dsk1chng &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;mkNixOSConfig &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;machines&#x2F;dsk1chng&#x2F;configuration.nix&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;svr1chng &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;mkNixOSConfig &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;machines&#x2F;svr1chng&#x2F;configuration.nix&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;svr2chng &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;mkNixOSConfig &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;machines&#x2F;svr2chng&#x2F;configuration.nix&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;svr3chng &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;mkNixOSConfig &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;machines&#x2F;svr3chng&#x2F;configuration.nix&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;iso1chng &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;nixosSystem {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;system &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;x86_64-linux&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;specialArgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;inputs outputs vars&lt;&#x2F;span&gt;&lt;span&gt;;};
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;modules &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;          (nixpkgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;nixos&#x2F;modules&#x2F;installer&#x2F;cd-dvd&#x2F;installation-cd-minimal.nix&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;machines&#x2F;iso1chng&#x2F;configuration.nix&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        ];
&lt;&#x2F;span&gt;&lt;span&gt;      };
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Each machine entry in &lt;code&gt;flake.nix&lt;&#x2F;code&gt; links to a folder that contains that
machine’s &lt;code&gt;configuration.nix&lt;&#x2F;code&gt; and &lt;code&gt;hardware-configuration.nix&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Even without much of a clear idea on how to use Nix or structure it, I had a
design goal that I should separate each distinct function that I wanted my
homelab to do into its own Nix file. Since several machines share parts of a
common configuration, any &lt;code&gt;configuration.nix&lt;&#x2F;code&gt; file is just a combination of
imported files plus a &lt;code&gt;vars&lt;&#x2F;code&gt; import for usernames and keys.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  inputs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  outputs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  vars&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;}: {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;imports &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;    inputs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;impermanence&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;nixosModules&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;impermanence
&lt;&#x2F;span&gt;&lt;span&gt;    inputs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;home-manager&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;nixosModules&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;home-manager
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;hardware-configuration.nix&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;..&#x2F;..&#x2F;modules&#x2F;nixos&#x2F;auto-update.nix&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;..&#x2F;..&#x2F;modules&#x2F;nixos&#x2F;base.nix&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;..&#x2F;..&#x2F;modules&#x2F;nixos&#x2F;remote-unlock.nix&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;..&#x2F;..&#x2F;services&#x2F;tailscale.nix&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;..&#x2F;..&#x2F;services&#x2F;nextcloud.nix&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  ];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;home-manager &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;extraSpecialArgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;inherit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;inputs outputs vars&lt;&#x2F;span&gt;&lt;span&gt;;};
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;useGlobalPkgs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;useUserPackages &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt;.${vars&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;userName}.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;imports &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.&#x2F;..&#x2F;..&#x2F;modules&#x2F;home-manager&#x2F;base.nix&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    ];
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;hostName &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;svr1chng&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;There is technically a more idiomatic way to go about doing this. Importing
Nix files works fine, but the official Nix repository activates configurations
by creating modules that let you activate via &lt;code&gt;config.&amp;lt;your module&amp;gt;.enable = true&lt;&#x2F;code&gt;. This nice person on Reddit kindly included some &lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;NixOS&#x2F;comments&#x2F;171cffr&#x2F;comment&#x2F;k3q243z&#x2F;&quot;&gt;examples of how this
works&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;For now, this is the structure that keeps my repository straightforward,
scalable across multiple machines, and economical as it concerns boilerplate
code. In my opinion, it’s also not overwhelmingly intimidating to new Nix users.
This structure means that my Nix files rarely exceed 100 lines and I don’t need
to nest directories more than two layers deep.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;remote-initrd-unlocking&quot;&gt;Remote initrd unlocking&lt;a class=&quot;zola-anchor&quot; href=&quot;#remote-initrd-unlocking&quot; aria-label=&quot;Anchor link for: remote-initrd-unlocking&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Recall from the above installation script that we generated an initrd host key.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  config&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  vars&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;}: {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;boot&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;kernelParams &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;ip=dhcp&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;boot&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;initrd&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;network &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;ssh &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;shell &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;bin&#x2F;cryptsetup-askpass&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;authorizedKeys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;config&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;users&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;users&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;${vars&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;userName}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;openssh&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;authorizedKeys&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;keys;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;hostKeys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;nix&#x2F;secret&#x2F;initrd&#x2F;ssh_host_ed25519_key&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Beware, using &lt;code&gt;boot.kernelParams = [&quot;ip=dhcp&quot;];&lt;&#x2F;code&gt; means you &lt;em&gt;must&lt;&#x2F;em&gt; be able to
supply an IP address to the machine during bootup, or else it won’t boot.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I had to modify my &lt;code&gt;hardware-configuration.nix&lt;&#x2F;code&gt; file to ensure my ethernet
driver was available to the initrd. You can see which driver your machine uses
by running &lt;code&gt;readlink &#x2F;sys&#x2F;class&#x2F;net&#x2F;&amp;lt;YOUR NETWORK INTERFACE&amp;gt;&#x2F;device&#x2F;driver&lt;&#x2F;code&gt; when
you’re in the NixOS installer ISO. I discovered that for my servers, it’s
&lt;code&gt;e1000e&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  config&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  modulesPath&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;}: {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;imports &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;    (modulesPath &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;installer&#x2F;scan&#x2F;not-detected.nix&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;  ];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;boot &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;initrd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# `readlink &#x2F;sys&#x2F;class&#x2F;net&#x2F;enp0s31f6&#x2F;device&#x2F;driver` indicates &amp;quot;e1000e&amp;quot; is the ethernet driver for this device
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;availableKernelModules &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nvme&amp;quot; &amp;quot;xhci_pci&amp;quot; &amp;quot;ahci&amp;quot; &amp;quot;usb_storage&amp;quot; &amp;quot;sd_mod&amp;quot; &amp;quot;e1000e&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;luks &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;reusePassphrases &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;devices &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;cryptroot&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;nvme0n1p2&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;allowDiscards &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          };
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;fun&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;sda1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;          };
&lt;&#x2F;span&gt;&lt;span&gt;        };
&lt;&#x2F;span&gt;&lt;span&gt;      };
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;fileSystems &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;none&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;fsType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;tmpfs&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;options &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;defaults&amp;quot; &amp;quot;size=4G&amp;quot; &amp;quot;mode=0755&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;boot&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;disk&#x2F;by-label&#x2F;boot&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;fsType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;vfat&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;options &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;umask=0077&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;nix&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;disk&#x2F;by-label&#x2F;nix&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;fsType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;ext4&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;fun&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;disk&#x2F;by-label&#x2F;fun&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;fsType &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;ext4&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;useDHCP &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;mkDefault &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;nixpkgs&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;hostPlatform &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;mkDefault &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;x86_64-linux&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;hardware&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;cpu&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;intel&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;updateMicrocode &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;lib&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;mkDefault config&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;hardware&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;enableRedistributableFirmware;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;unattended-upgrades&quot;&gt;Unattended upgrades&lt;a class=&quot;zola-anchor&quot; href=&quot;#unattended-upgrades&quot; aria-label=&quot;Anchor link for: unattended-upgrades&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I also set up a GitHub action bot on my repository that updates my &lt;code&gt;flake.lock&lt;&#x2F;code&gt;
file daily. I wrote a file called &lt;code&gt;auto-update.nix&lt;&#x2F;code&gt; that, as you guessed, can
automatically update a NixOS system by reading from the tip of my repository’s
commit tree.&lt;&#x2F;p&gt;
&lt;p&gt;This is the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;eh8&#x2F;chenglab&#x2F;blob&#x2F;main&#x2F;.github&#x2F;workflows&#x2F;flake.yml&quot;&gt;GitHub action
YAML&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yml&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-yml &quot;&gt;&lt;code class=&quot;language-yml&quot; data-lang=&quot;yml&quot;&gt;&lt;span&gt;---
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# inspo: https:&#x2F;&#x2F;github.com&#x2F;reckenrode&#x2F;nixos-configs&#x2F;blob&#x2F;main&#x2F;.github&#x2F;workflows&#x2F;main.yml
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;Bump flake.lock&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;schedule&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# 10am UTC is 6am EDT&#x2F;5am EST
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;cron&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;0 10 * * *&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;workflow_dispatch&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;null
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;runs-on&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;ubuntu-latest&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;steps&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;uses&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;actions&#x2F;checkout@v6&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;fetch-depth&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;uses&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;cachix&#x2F;install-nix-action@v31&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;nix flake update&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;uses&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;stefanzweifel&#x2F;git-auto-commit-action@v7&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;commit_message&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;chore(deps): bump flake.lock&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;commit_user_name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;Flake Bot&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;commit_options&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;--no-verify --signoff&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;commit_author&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;Flake Bot &amp;lt;actions@github.com&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;branch&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;file_pattern&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;flake.lock&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;skip_dirty_check&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;skip_fetch&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And here’s the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;eh8&#x2F;chenglab&#x2F;blob&#x2F;main&#x2F;modules&#x2F;nixos&#x2F;auto-update.nix&quot;&gt;Nix
config&lt;&#x2F;a&gt;
that manages unattended upgrades:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-nix &quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# inspo: https:&#x2F;&#x2F;github.com&#x2F;reckenrode&#x2F;nixos-configs&#x2F;blob&#x2F;main&#x2F;hosts&#x2F;meteion&#x2F;configuration.nix
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;system&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;autoUpgrade &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;enable &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;dates &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*-*-* 07:00:00&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;randomizedDelaySec &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;1h&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#92caf4;&quot;&gt;flake &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;github:eh8&#x2F;chenglab&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;a class=&quot;zola-anchor&quot; href=&quot;#acknowledgments&quot; aria-label=&quot;Anchor link for: acknowledgments&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;For beginners, &lt;a href=&quot;https:&#x2F;&#x2F;nixos-and-flakes.thiscute.world&quot;&gt;this was an excellent
resource&lt;&#x2F;a&gt; to learn more about NixOS and
flakes.&lt;&#x2F;p&gt;
&lt;p&gt;Manuel Hutter’s blog post &lt;a href=&quot;https:&#x2F;&#x2F;mhu.dev&#x2F;posts&#x2F;2024-01-06-nixos-on-hetzner&#x2F;&quot;&gt;NixOS on Hetzner
Dedicated&lt;&#x2F;a&gt; was both timely
and useful. It inspired large parts of my own install script.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;impermanence&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;When combined, NixOS’s declarative configuration paradigm and
impermanence mean that adding and removing modules from a machine’s
&lt;code&gt;configuration.nix&lt;&#x2F;code&gt; will not leave any residual files or state on the
machine. This is super handy for testing out new software.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;iso&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;At time of writing, you’ll need to do this from an x86_64 computer. So I
just installed NixOS on a desktop to be able to create my custom ISO.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;tailscale&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;By using the server hostname rather than its IP address, I can
avoid the host key collision that makes SSH complain.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;starter&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;I use &lt;a href=&quot;https:&#x2F;&#x2F;cursor.sh&#x2F;&quot;&gt;Cursor&lt;&#x2F;a&gt; as my main code editor, which is
a fork of Visual Studio Code. I use the &lt;a href=&quot;https:&#x2F;&#x2F;marketplace.cursorapi.com&#x2F;items?itemName=kamadorueda.alejandra&quot;&gt;Alejandra
💅&lt;&#x2F;a&gt;
extension to automatically format my Nix code whenever I save the file. I
also use &lt;a href=&quot;https:&#x2F;&#x2F;marketplace.cursorapi.com&#x2F;items?itemName=jnoortheen.nix-ide&quot;&gt;Nix
IDE&lt;&#x2F;a&gt;
for language server support. These two extensions make life much better when
developing with Nix.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Is anyone home?</title>
        <published>2024-03-04T00:00:00+00:00</published>
        <updated>2024-03-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/commit/"/>
        <id>https://www.chengeric.com/commit/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/commit/">&lt;p&gt;I occasionally come across GitHub repositories that haven’t been updated in
months or years. A package or script that doesn’t appear to be actively
maintained makes me hesitate to use it. Even if I was inclined to contribute,
I’m not sure if the author would still accept a pull request.&lt;&#x2F;p&gt;
&lt;p&gt;Having dependabot or a something similar is a good start, but I’ve still come
across zombie projects whose dependencies were kept updated but functionalities
were already broken.&lt;&#x2F;p&gt;
&lt;p&gt;We need a way to quickly signal to the passing observer that software is still
in a sustainment mode. One solution is to periodically update your README file
to something of the following effect:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Update 2024-03: this project does not have any active features in development,
but is nonetheless still maintained to address any breaking changes upstream.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>0.3% of American taxes supported Ukraine last year</title>
        <published>2023-08-30T00:00:00+00:00</published>
        <updated>2023-08-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/ukraine/"/>
        <id>https://www.chengeric.com/ukraine/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/ukraine/">&lt;p&gt;Politics and ethics aside, the national debate over American aid to Ukraine
often implies such aid is very costly to the average American taxpayer.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;&#x2F;strong&gt; It’s not. The median American paid about $30 last year.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;overview-of-us-support-for-ukraine&quot;&gt;Overview of US support for Ukraine&lt;a class=&quot;zola-anchor&quot; href=&quot;#overview-of-us-support-for-ukraine&quot; aria-label=&quot;Anchor link for: overview-of-us-support-for-ukraine&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;As of January 2022 to May 2023, the United States has provided &lt;a href=&quot;https:&#x2F;&#x2F;www.cfr.org&#x2F;article&#x2F;how-much-aid-has-us-sent-ukraine-here-are-six-charts&quot;&gt;$76 billion in
aid to
Ukraine.&lt;&#x2F;a&gt;
Notably, over 60% of this is military aid predominantly from decommissioned
equipment stockpiles. Since such weaponry &lt;em&gt;generally&lt;&#x2F;em&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#militaryaid&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; doesn’t need
to be replenished, I’ve discarded military aid from the rest of the calculation.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Remember this when you see the now-typical news headline “US approves \(X\)
billion in &lt;strong&gt;military aid&lt;&#x2F;strong&gt; to Ukraine”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Deducting the military aid leaves us with $30 billion in financial and
humanitarian aid, often dubbed as the “cash” sent to Ukraine. While some of this
emanates from pre-existing federal budgets like the Economic Support Fund, let’s
just assume for clarity and conservative estimation that we directed a cash
equivalent of $30 billion to Ukraine.&lt;&#x2F;p&gt;
&lt;p&gt;But remember, this figure represents 492 days from January 2022 to May 2023.
We’re just talking about how much the average American taxpayer hypothetically
pays &lt;em&gt;in a single year.&lt;&#x2F;em&gt; So we need to annualize this amount to match which
gives us an adjusted figure of just under $22.5 billion.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;government-revenue-and-spending&quot;&gt;Government revenue and spending&lt;a class=&quot;zola-anchor&quot; href=&quot;#government-revenue-and-spending&quot; aria-label=&quot;Anchor link for: government-revenue-and-spending&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The median American &lt;a href=&quot;https:&#x2F;&#x2F;taxfoundation.org&#x2F;data&#x2F;all&#x2F;federal&#x2F;summary-latest-federal-income-tax-data-2023-update&#x2F;&quot;&gt;paid $10,845 in income
taxes&lt;&#x2F;a&gt;
in 2020. Since this is the latest available data from the IRS, I’m going to
assume it’s consistent with the present day.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;fiscaldata.treasury.gov&#x2F;americas-finance-guide&#x2F;&quot;&gt;The Treasury reports&lt;&#x2F;a&gt;
that in FY 2022:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Total government revenue was $4.9 trillion, of which $2.6 trillion was
individual income tax.&lt;&#x2F;li&gt;
&lt;li&gt;Total government spending was $6.3 trillion.&lt;&#x2F;li&gt;
&lt;li&gt;Social Security and Medicare (FICA) tax revenue amounted to $1.5 trillion.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;FY 2022 started October 1, 2021 and ended September 30, 2022. As the
full-scale invasion of Ukraine began on February 24, 2022, this doesn’t
perfectly align but it’s good enough.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;a class=&quot;zola-anchor&quot; href=&quot;#putting-it-all-together&quot; aria-label=&quot;Anchor link for: putting-it-all-together&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;br&gt;
&lt;p&gt;\( \text{Individual income tax} \times \frac{\text{total income tax
revenue}}{\text{total revenue} - \text{total FICA}} \times
\frac{\text{annualized aid to Ukraine}}{\text{total spending}} \)&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;p&gt;\( =\text{\$10,845} \times \frac{\text{\$2.6 trillion}}{\text{\$4.9
trillion} - \text{\$1.5 trillion}} \times \frac{\text{\$22.5
billion}}{\text{\$6.3 trillion}} \)&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;p&gt;\( =\text{\$29.90} \)&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;p&gt;The median American taxpayer’s support for Ukraine in FY 2022 was $29.90. That’s
0.28% of the total income tax owed, hence the title of this blog post.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;So for every $1 you pay in income tax, $0.0028 will head to Ukraine as
financial and humanitarian support.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Here’s a table showing the differences in contribution across a variety of
income levels:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Income percentile&lt;&#x2F;th&gt;&lt;th&gt;Median income tax paid&lt;&#x2F;th&gt;&lt;th&gt;Annual contribution to Ukraine&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;All taxpayers&lt;&#x2F;td&gt;&lt;td&gt;$10,845&lt;&#x2F;td&gt;&lt;td&gt;$29.90&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;bottom 50%&lt;&#x2F;td&gt;&lt;td&gt;$504&lt;&#x2F;td&gt;&lt;td&gt;$1.39&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;top 50%&lt;&#x2F;td&gt;&lt;td&gt;$21,187&lt;&#x2F;td&gt;&lt;td&gt;$58.41&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;top 25%&lt;&#x2F;td&gt;&lt;td&gt;$38,396&lt;&#x2F;td&gt;&lt;td&gt;$105.86&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;top 10%&lt;&#x2F;td&gt;&lt;td&gt;$79,897&lt;&#x2F;td&gt;&lt;td&gt;$220.27&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;top 5%&lt;&#x2F;td&gt;&lt;td&gt;$136,091&lt;&#x2F;td&gt;&lt;td&gt;$375.20&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;top 1%&lt;&#x2F;td&gt;&lt;td&gt;$458,894&lt;&#x2F;td&gt;&lt;td&gt;$1,265.16&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;For a deeper dive, you can check &lt;a href=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;scl&#x2F;fi&#x2F;a5z7geogppd1ltyd07j8e&#x2F;US-taxpayer-contribution-to-Ukraine.xlsx?rlkey=pdlcclkgfj7be092o42u2rdgf&amp;amp;dl=0&quot;&gt;my
spreadsheet&lt;&#x2F;a&gt;
to verify the calculations yourself.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;my-personal-thoughts&quot;&gt;My personal thoughts&lt;a class=&quot;zola-anchor&quot; href=&quot;#my-personal-thoughts&quot; aria-label=&quot;Anchor link for: my-personal-thoughts&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The real cost of supporting Ukraine surprised me—it’s significantly less than
one might presume from public discourse.&lt;&#x2F;p&gt;
&lt;p&gt;Some other concluding thoughts:&lt;&#x2F;p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;For the bottom 50% of Americans, aid to Ukraine is virtually negligible.&lt;&#x2F;li&gt;
&lt;li&gt;For the median American taxpayer, the monthly outlay for Ukraine of $2.50 is
about the same price as a bag of potato chips.&lt;&#x2F;li&gt;
&lt;li&gt;For the top 10% earners, it’s akin to a yearly Netflix Premium subscription.&lt;&#x2F;li&gt;
&lt;li&gt;The US is estimated to be &lt;a href=&quot;https:&#x2F;&#x2F;www.cfr.org&#x2F;article&#x2F;how-much-aid-has-us-sent-ukraine-here-are-six-charts&quot;&gt;spending 0.33% of
GDP&lt;&#x2F;a&gt;
to help defend Ukraine. In comparison, spending for the Iraq War is estimated
to have peaked at 1% of GDP, and needless to say far overshadows Ukraine in
terms of costs and US casualties.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#economist&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#iraqwar&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; For perspective, the
US spent over 50% of GDP at the height of World War II.&lt;&#x2F;li&gt;
&lt;li&gt;Even if my calculations were egregiously inaccurate by a factor of two or
more, the cost would still be modest given the media sensationalism and how
high-profile the war is.&lt;&#x2F;li&gt;
&lt;li&gt;This exercise relates the unfamiliar concept of federal government spending
with the familiar concept of household budgeting. But like any analogy, we
should recognize its limitations.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#recommendedreading&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; You might wonder
&lt;em&gt;“jeez, if supporting Ukraine is really this cheap, then why can’t we do the
same for XYZ?”&lt;&#x2F;em&gt; Well, that’s a political and ethical discussion beyond the
scope of this topic. But I would argue that from a government’s perspective,
funding ABC does not create the kind of opportunity cost for XYZ that you
might encounter as an individual. Moreover, the government doesn’t raise
income tax rates in response to higher spending.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Speaking more freely, given the stark moral and geopolitical implications of the
conflict, I urge you to &lt;a href=&quot;https:&#x2F;&#x2F;u24.gov.ua&#x2F;&quot;&gt;support Ukraine via United24&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;militaryaid&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Sure, some equipment being sent to Ukraine, such as the planned
delivery of the Abrams main battle tank, isn’t coming from excess stock and
likely needs to be replenished. But crucially, this invasion has prompted
militaries around the globe to refocus on conventional warfare capabilities.
This rearmament is occuring regardless of a nation’s stance towards Ukraine.
So whether or not the US chooses to actively support Ukraine with expensive
Western drones, tanks, or jets is irrelevant, since it almost certaintly
would have otherwise sent such things to bolster NATO allies in Eastern
Europe.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;economist&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.economist.com&#x2F;graphic-detail&#x2F;2023&#x2F;05&#x2F;30&#x2F;how-much-is-russia-spending-on-its-invasion-of-ukraine&quot;&gt;How much is Russia spending on its invasion of
Ukraine?&lt;&#x2F;a&gt;
by the Economist&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;iraqwar&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.brown.edu&#x2F;news&#x2F;2021-09-01&#x2F;costsofwar&quot;&gt;Costs of the 20-year war on terror: $8 trillion and 900,000
deaths&lt;&#x2F;a&gt; by Brown
University&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;recommendedreading&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;If you found this blog post interesting, I would also
recommend NASA director Dr. Ernst Stuhlinger’s 1971 letter to a nun asking
&lt;a href=&quot;https:&#x2F;&#x2F;lettersofnote.com&#x2F;2012&#x2F;08&#x2F;06&#x2F;why-explore-space&#x2F;&quot;&gt;why explore space when there are so many starving children on
Earth?&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Request for startup: peer-to-peer backups</title>
        <published>2023-08-29T00:00:00+00:00</published>
        <updated>2023-08-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/stackrooms/"/>
        <id>https://www.chengeric.com/stackrooms/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/stackrooms/">&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Stackrooms does not actually exist &lt;em&gt;(yet!)&lt;&#x2F;em&gt;.&lt;&#x2F;strong&gt; I wrote this doc back in mid-2022 expecting to devote significantly more time to it after graduating. I bought the domain name and have played around with small fragments of a Golang proof-of-concept in my free time. Sadly, most of the code (which was nothing special) was on a storage drive that I accidentally overwrote before I cared enough to upload it to GitHub. Very ironic that I didn’t backup my own backup software.&lt;&#x2F;p&gt;
&lt;p&gt;Since Microsoft employees get a bunch of &lt;a href=&quot;https:&#x2F;&#x2F;azure.microsoft.com&#x2F;en-us&#x2F;pricing&#x2F;member-offers&#x2F;credit-for-visual-studio-subscribers&#x2F;&quot;&gt;free Azure credits&lt;&#x2F;a&gt;, my personal desire to solve this problem has diminished.&lt;&#x2F;p&gt;
&lt;p&gt;But ideas are cheap, and execution is far more valuable. I’m publishing this article now since another homelab enthusiast (like you) might find this problem worth solving.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Stackrooms is a peer-to-peer backup platform. Here are the main points:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;You contribute \(n\) gigabytes of server storage to host other users’ backups, and in turn you receive \( \frac{n}{2} \) gigabytes of storage to back up your own data.&lt;&#x2F;li&gt;
&lt;li&gt;You can back up as much data as you like, so long as you can supply commensurate storage space.&lt;&#x2F;li&gt;
&lt;li&gt;Our matchmaking system optimizes for the fastest latency and farthest geographic distance between peers.&lt;&#x2F;li&gt;
&lt;li&gt;Data is encrypted both in transit and at rest, which means only you can read your data. Neither we nor your hosts can read your data at anytime.&lt;&#x2F;li&gt;
&lt;li&gt;The Stackrooms client can happily run on a tiny Raspberry Pi, a decked-out rackmount server, and anything else that has access to the internet.&lt;&#x2F;li&gt;
&lt;li&gt;We offer a free tier for personal use and provide a range of options to accommodate your team and backup requirements.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;mutually-assured-recovery&quot;&gt;Mutually assured recovery&lt;a class=&quot;zola-anchor&quot; href=&quot;#mutually-assured-recovery&quot; aria-label=&quot;Anchor link for: mutually-assured-recovery&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The Stackrooms client regularly checks the integrity of your backup. In the event one of your backup peers are unresponsive for an extended period of time, we support an automatic fail-over mechanism to keep your data safe on a fresh backup peer. Conversely, if you are unable to continue backing up other users’ data, we ensure your data remains ready to restore for up to 30 days.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;frustration-free-packaging&quot;&gt;Frustration-free packaging&lt;a class=&quot;zola-anchor&quot; href=&quot;#frustration-free-packaging&quot; aria-label=&quot;Anchor link for: frustration-free-packaging&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Restoring a backup shouldn’t be a sweaty, nail-biting odyssey. Using Stackrooms to retrieve data is a fast and intuitive experience. We aim to provide a first-class user experience on both a fast web interface and an ergonomic command line interface.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;flavors-for-everybody&quot;&gt;Flavors for everybody&lt;a class=&quot;zola-anchor&quot; href=&quot;#flavors-for-everybody&quot; aria-label=&quot;Anchor link for: flavors-for-everybody&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Anybody can use the Stackrooms free tier for their own personal use.&lt;&#x2F;strong&gt; We are enthusiastic about getting Stackrooms into the hands of individuals who can spread the merry menu of Stackrooms to their friends and colleagues. Free users improve the density of the Stackrooms network, while users get a safe place to store their data. This is a win-win for all parties involved.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;For larger deployments, we offer different paid tiers that scale by the number of users in your organization.&lt;&#x2F;strong&gt; This is a radically different pricing model than conventional backup services, which charge you by the amount of storage you’ve used.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Our goal is to make backups as accessible as possible.&lt;&#x2F;strong&gt; Try Stackrooms today, and see what you think!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;a class=&quot;zola-anchor&quot; href=&quot;#motivation&quot; aria-label=&quot;Anchor link for: motivation&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The idea that I could do a comparable job self-hosting my file storage, Git repositories, or websites at a much lower cost than paying for the same service from a big technology company was very exciting. The realization that I would still have pay to backup my critical data in the Cloud™ was a bit of a let-down, because it meant conceding some of my aspirations. Stackrooms is trying to change this dynamic.&lt;&#x2F;p&gt;
&lt;p&gt;The idea of a peer-to-peer storage network isn’t novel. Some peer-to-peer storage systems rely upon paying people to lend their powerful storage servers. However, this creates two issues: a barrier to entry and a brittle long-run incentive.&lt;&#x2F;p&gt;
&lt;p&gt;But backups are an elegant usecase for Stackrooms, because they encourage both consumption and contribute to the Stackrooms network. This is the principle behind our tongue-in-cheek principle of &lt;em&gt;mutually assured recovery&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;privacy&quot;&gt;Privacy&lt;a class=&quot;zola-anchor&quot; href=&quot;#privacy&quot; aria-label=&quot;Anchor link for: privacy&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In some key ways, Stackrooms behaves like a multiplayer video game. You team up with other ‘players’ and are placed into a ‘lobby’ via a matchmaking mechanism. But instead of playing a game, you back up each others’ data.&lt;&#x2F;p&gt;
&lt;p&gt;Good player discoverability and prompt updates are traits of a good video game. Bringing this analogy back to us, we operate a centralized platform to ensure users can connect to each other quickly and have easy access to cool features in the future.&lt;&#x2F;p&gt;
&lt;p&gt;We want to build a product that people enjoy using — a product that can be sustainably commercialized without compromising user privacy. As such, the Stackrooms client is open source and we retain as little information as possible when connecting peers together. There is arguably nothing more important to a startup than our own reputation, which is why we will vigorously defend your expectations of privacy. Stackrooms is the product, not you.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Too many awful stock trading apps</title>
        <published>2023-04-13T00:00:00+00:00</published>
        <updated>2023-04-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/trading-apps/"/>
        <id>https://www.chengeric.com/trading-apps/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/trading-apps/">&lt;p&gt;Last year, I wrote about the &lt;a href=&quot;https:&#x2F;&#x2F;chengeric.com&#x2F;investing&#x2F;&quot;&gt;index fund investing
strategy&lt;&#x2F;a&gt; I would recommend to anybody. But I
must admit that arriving to such a strategy is not a natural step for most
people. Index funds are quite boring and don’t have the backing to advertise
themselves on TikTok or Times Square. They represent an investing style that
stands in stark contrast to what the majority of new, glitzy trading apps
promote. And it is these such apps that unfortunately tend to attract young or
inexperienced investors.&lt;&#x2F;p&gt;
&lt;p&gt;There are no shortage of terrible apps that let you trade stocks and crypto from
the comfortable cliff ledge of your smartphone. And yet, overwhelming research
shows that the average investor cannot pick stocks, cannot learn from their
mistakes, and cannot earn their money back once its lost.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Not every app
sucks, but most of these new wave trading apps build their user interface and
features for the sole purpose of encouraging their customers to trade as
frequently as possible. While the company behind the app earns a little bit of
money from &lt;a href=&quot;https:&#x2F;&#x2F;www.investopedia.com&#x2F;terms&#x2F;p&#x2F;paymentoforderflow.asp&quot;&gt;payment for order flow
(PFOF)&lt;&#x2F;a&gt; on each and
every trade, the average user will tend to lose money as they trade more and
more.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;These apps induce some of the &lt;a href=&quot;&#x2F;badinvesting&quot;&gt;worst behaviorial mistakes&lt;&#x2F;a&gt; of
investing by employing so many dark patterns. Generally speaking, an app that
advertises itself for new, young investors is really meant for new, reckless
traders. So what can we learn from all of this?&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don’t get distracted by a polished UI.&lt;&#x2F;strong&gt; A hyper-gamified user interface
that places heavy emphasis on real-time gains and losses is great for increasing
customer retention, but drives people towards obsessing about their portfolios
to an unhealthy extent.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don’t get distracted by free trades.&lt;&#x2F;strong&gt; Commission-free trading should
ostensibly help customers save money, but instead makes it psychologically
easier to dart in and out of positions recklessly. Use this feature responsibly.
Don’t think a trading app is trying to be generous by granting you free trades
for your stocks or options. After all, casinos offer free drinks and appetizers
to players on the slot machine, too.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don’t get distracted by fake financial prophets.&lt;&#x2F;strong&gt; The company research
articles listed under each stock are practically useless since any noteworthy
corporate events are literally priced into a stock by the time they are
published to a mainstream news publication. They also tend to be very
click-baity and read as if they were written by some stupid robot. Reading those
articles for their financial advices is like getting medical advice from
supermarket checkout line tabloids.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;It is sadly easy to fool people into thinking they can learn how to trade
stocks. People tend to mistake their gains, if any, as evidence of their
superior sense of market timing or unique industry knowledge. But this hubris is
not attributable to skill, but rather to sheer luck that the past decade was
simply a bull run. And lots of people still somehow &lt;em&gt;lost&lt;&#x2F;em&gt; money despite living
in a rising market.&lt;&#x2F;p&gt;
&lt;p&gt;Let me cherrypick the one app in particular that pretty much kickstarted this
all: &lt;em&gt;Robinhood.&lt;&#x2F;em&gt; It advertises itself as &lt;em&gt;democratizing finance&lt;&#x2F;em&gt;, but Robinhood
instead dramatizes finance by fooling the public into thinking they can become
consistently successful traders. Seeing designers get excited over Robinhood’s
user interface is a modern-day equivalent of 1960s designers fawning over
Marlboro’s TV commerciais.&lt;&#x2F;p&gt;
&lt;p&gt;I would go so far as to say that Robinhood has probably destroyed more of its
users’ wealth than it has created. Which is ironic given its name.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The original version of this article was posted on March 5, 2023. I revised it
significantly on April 13, 2023.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;faculty.haas.berkeley.edu&#x2F;odean&#x2F;papers&#x2F;Day%20Traders&#x2F;Day%20Trading%20and%20Learning%20110217.pdf&quot;&gt;Do Day Traders Rationally Learn About Their
Ability?&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;papers.ssrn.com&#x2F;sol3&#x2F;papers.cfm?abstract_id=3715077&quot;&gt;Attention-Induced Trading and Returns: Evidence from Robinhood
Users&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Famous FPS maps tend to be sunny</title>
        <published>2023-03-22T00:00:00+00:00</published>
        <updated>2023-03-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/sunny/"/>
        <id>https://www.chengeric.com/sunny/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/sunny/">





























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;2fort.bd837712364abf27.jpg&quot;
        class=&quot;&quot; alt=&quot;2fort&quot;  width=1167 &#x2F;&gt;
    &lt;figcaption&gt;2Fort, Team Fortress 2 (2007).&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;





























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;dust2.da9a84eccb28ae8e.jpg&quot;
        class=&quot;&quot; alt=&quot;dust2&quot;  width=1167 &#x2F;&gt;
    &lt;figcaption&gt;Dust II, Counter-Strike: Global Offensive (2012).&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;





























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;bf4.5e145a34ac606b69.jpg&quot;
        class=&quot;&quot; alt=&quot;siege of shanghai&quot;  width=1167 &#x2F;&gt;
    &lt;figcaption&gt;Siege of Shanghai, Battlefield 4 (2013).&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;





























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;nuketown.7ae073938a15d6a4.jpg&quot;
        class=&quot;&quot; alt=&quot;nuketown&quot;  width=1167 &#x2F;&gt;
    &lt;figcaption&gt;Nuketown, Call of Duty: Black Ops (2010).&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;





























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;halo.acd944de222f0a13.jpg&quot;
        class=&quot;&quot; alt=&quot;blood gulch&quot;  width=1167 &#x2F;&gt;
    &lt;figcaption&gt;Blood Gulch, Halo: Combat Evolved (2001).&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>GPT will not end documentation</title>
        <published>2023-03-19T00:00:00+00:00</published>
        <updated>2023-03-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/gpt-documentation/"/>
        <id>https://www.chengeric.com/gpt-documentation/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/gpt-documentation/">&lt;p&gt;Writing software completely from scratch is inefficient. That’s why it’s so
important that documentation includes plenty of example code. Developers seeking
to onboard new users to their fancy new framework have more or less figured this
out.&lt;&#x2F;p&gt;
&lt;p&gt;But things are starting to change. Without having to browse documentation or
Stack Overflow first, I can instead ask a free chatbot to write some code for me
in a language I don’t fully understand and then iterate as needed, undercutting
the need to dive into documentation as deeply or frequently as I would otherwise
need to. Does this mean documentation is outdated?&lt;&#x2F;p&gt;
&lt;p&gt;No.&lt;&#x2F;p&gt;
&lt;p&gt;In fact, documentation will probably become even more important as it starts to
serve not only humans, but LLMs too. In a few short years, we may see developers
specifically advertising how their language, npm package, or API works well with
GPT-X. Artificial intelligence will provide a basic scaffold for a software
project, but it will still be the responsibility of the humble human developer
to write the complex bits. And whether both parties are capable of fulfilling
their role will still require thorough documentation to do so. In theory, this
should actually &lt;em&gt;encourage&lt;&#x2F;em&gt; developers to describe their software very
explicitly to help the AI understand its functionality, in much the same way
people try to use SEO techniques to make their food blogs more visible to search
engines.&lt;&#x2F;p&gt;
&lt;p&gt;I hope it doesn’t happen, but I wouldn’t be surprised if OpenAI sold a
“GPT-ready” certification to companies trying to woo developers by showing how
fine-tuned and calibrated GPT is when handling their software.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Bad investing</title>
        <published>2022-11-04T00:00:00+00:00</published>
        <updated>2022-11-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/bad-investing/"/>
        <id>https://www.chengeric.com/bad-investing/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/bad-investing/">
































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;iceberg.d73b13ee23716976.jpg&quot;
        class=&quot;&quot; alt=&quot;iceberg&quot;  width=677 &#x2F;&gt;
    &lt;figcaption&gt;Some of the worst investing mistakes are only subtly wrong, which makes
them very dangerous.&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I do whatever my employer, family, or friends recommend because I don’t care
about investing.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I shouldn’t enter the market now because prices are about to drop further.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I shouldn’t enter the market now because prices are way too high.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I should exit the market now because prices are about to drop very soon.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I shouldn’t hold index funds because they only produce average returns.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I can validate my trading decisions by seeking affirmation on Reddit.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I only need to hold TSLA.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I only need to hold the S&amp;amp;P 500.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I only need to hold US companies.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I monitor my investments daily.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I believe my company will do really, really well in the future. When my RSUs
vest, I’m holding onto my company shares.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I want to get rid of this shitty stock, but I’ll sell when it finally recovers
to the price I bought in at.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I will never change my brokerage.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I prefer to invest in a taxable account because I don’t want to pay an early
withdrawal penalty on a retirement account if I need the money sooner.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I’ll buy this stock because all my friends and everybody on social media is
getting rich off of it.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I should gradually invest this pile of cash instead of all at once.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I should read &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;ub82Xb1C8os&quot;&gt;cnbc.com&lt;&#x2F;a&gt; regularly to become a
better investor.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I should always hold my international stocks in a taxable account because of
the foreign tax credit.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I shouldn’t invest at all because everything’s rigged against me.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I shouldn’t invest at all because the world is going to end anyway.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I believe that paying a financial advisor is worth it, because this particular
advisor has outperformed the market for the past ten years.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I should buy 3X leveraged ETFs to boost my return, since the market always
goes up in the long run.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I should buy LEAPS because the market will always go up in the long run.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I won’t sell this penny stock because I already earned a 900% return and it
will continue to grow.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I should invest in stocks that produce the most dividends.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I consider an investment decision wise as long as it made money.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I judge my investing decisions based on realized returns instead of expected
returns.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I know what the market is going to do in the next &lt;code&gt;$TIMEFRAME&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I think I can trade options because I’m built different.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I think I can trade stocks because I’m a tough investor.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I think I can trade stocks because I follow
&lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;ub82Xb1C8os&quot;&gt;seekingalpha.com&lt;&#x2F;a&gt; bloggers for investment
recommendations.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I think I can trade stocks.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;There is surely somebody out there who has done very well despite making every
single one of these mistakes. But that person isn’t you or me.&lt;&#x2F;p&gt;
&lt;p&gt;To be continued.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Chinese restaurant theorem</title>
        <published>2022-10-29T00:00:00+00:00</published>
        <updated>2022-10-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/chinese-restaurant/"/>
        <id>https://www.chengeric.com/chinese-restaurant/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/chinese-restaurant/">&lt;p&gt;\[ \alpha = \frac{1}{Q_p} \]&lt;&#x2F;p&gt;
&lt;p&gt;where \( \alpha \) is the quality of the food and \( Q_p \) is the quantity
of paper towels in the bathroom. This theorem is only valid in the United
States.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Simple investing</title>
        <published>2022-10-18T00:00:00+00:00</published>
        <updated>2022-10-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/investing/"/>
        <id>https://www.chengeric.com/investing/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/investing/">






&lt;blockquote style=&quot;display:flex;padding:1em;&quot;&gt;
    &lt;div style=&quot;padding-right:1em;flex-shrink:0;&quot;&gt;
        &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;sunzi.5f552e5612a93deb.jpg&quot; style=&quot;border-radius:50%;&quot; &#x2F;&gt;
    &lt;&#x2F;div&gt;
    &lt;div&gt;
        &lt;p style=&quot;margin:0;&quot;&gt;
            &lt;b&gt;Sun
Tzu&lt;&#x2F;b&gt;
            
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin-top:0;&quot;&gt;
            Win first, then fight.
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin:0;&quot; class=&quot;timestamp&quot;&gt;
            
            &lt;a href=https:&amp;#x2F;&amp;#x2F;ctext.org&amp;#x2F;art-of-war&amp;#x2F;tactical-dispositions?searchu=%E6%98%AF%E6%95%85%E5%8B%9D%E5%85%B5%E5%85%88%E5%8B%9D%EF%BC%8C%E8%80%8C%E5%BE%8C%E6%B1%82%E6%88%B0%EF%BC%9B%E6%95%97%E5%85%B5%E5%85%88%E6%88%B0%EF%BC%8C%E8%80%8C%E5%BE%8C%E6%B1%82%E5%8B%9D%E3%80%82&gt;☀ The Art of War&lt;&#x2F;a&gt;
            
        &lt;&#x2F;p&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;A solid portfolio is built on three pillars:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;A US total market index fund&lt;&#x2F;li&gt;
&lt;li&gt;An international total market index fund&lt;&#x2F;li&gt;
&lt;li&gt;A bond total market index fund&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is commonly called a &lt;em&gt;three-fund portfolio.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You can exclusively buy equities until you’re about twenty years away from
retirement because you can outlive a few market crashes by the time you retire.
Hence, a solid portfolio for your 20s and 30s is actually built on only two
pillars:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;A US total market index fund&lt;&#x2F;li&gt;
&lt;li&gt;An international total market index fund&lt;&#x2F;li&gt;
&lt;li&gt;&lt;del&gt;A bond total market index fund&lt;&#x2F;del&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;When you are ten years from retirement, I recommend a portfolio allocation of
70% stocks and 30% bonds.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that 70% and 30% are arbitrary percentages that balance the higher
expected returns of stocks and the lower risk of bonds. You can adjust to an
allocation that matches &lt;a href=&quot;https:&#x2F;&#x2F;www.bogleheads.org&#x2F;wiki&#x2F;Asset_allocation#Impact_of_asset_allocation_on_risk_and_return&quot;&gt;your objectives and risk
tolerance.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Allocation example&lt;&#x2F;th&gt;&lt;th&gt;at age 22&lt;&#x2F;th&gt;&lt;th&gt;at age 55&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;US index fund&lt;&#x2F;td&gt;&lt;td&gt;60%&lt;&#x2F;td&gt;&lt;td&gt;42%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;International index fund&lt;&#x2F;td&gt;&lt;td&gt;40%&lt;&#x2F;td&gt;&lt;td&gt;28%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Bond index fund&lt;&#x2F;td&gt;&lt;td&gt;0%&lt;&#x2F;td&gt;&lt;td&gt;30%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Of the total amount of stocks you own, 60% should be in the US total market
index fund and the remaining 40% in the total international index fund.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that 60% and 40% are not arbitrary percentages. These figures are the
&lt;a href=&quot;https:&#x2F;&#x2F;investor.vanguard.com&#x2F;investment-products&#x2F;etfs&#x2F;profile&#x2F;vt&quot;&gt;actual
proportions&lt;&#x2F;a&gt;
of US and international equities. Of course, these weights will shift over
time, and you &lt;em&gt;should&lt;&#x2F;em&gt; adjust your future contributions to match.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Contribute money to your portfolio as often and as much as you can, as early as
possible. If your personal situation permits, max out your 401(k) as early as
possible during the year. Try to set a goal like “I will invest \(x\) dollars
each paycheck&#x2F;week&#x2F;month.” Of course, remember to live your life and spend your
hard-earned money on the things and people that matter to you. Not every
decision in life needs to be driven by intense financial decision-making, but
you must still acknowledge the financial consequences of your choices.&lt;&#x2F;p&gt;
&lt;p&gt;If you have a burning desire to invest in something with a high risk-reward
ratio, allocate no more than 5% of your entire portfolio to try and dip your
speculative toes in whatever it is: individual stocks or cryptocurrencies or
NFTs or whatever.&lt;&#x2F;p&gt;





&lt;blockquote style=&quot;display:flex;padding:1em;&quot;&gt;
    &lt;div style=&quot;padding-right:1em;flex-shrink:0;&quot;&gt;
        &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;sunzi.5f552e5612a93deb.jpg&quot; style=&quot;border-radius:50%;&quot; &#x2F;&gt;
    &lt;&#x2F;div&gt;
    &lt;div&gt;
        &lt;p style=&quot;margin:0;&quot;&gt;
            &lt;b&gt;Sun Tzu&lt;&#x2F;b&gt;
            
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin-top:0;&quot;&gt;
            A mighty warrior maximizes
tax-advantaged account contributions.
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin:0;&quot; class=&quot;timestamp&quot;&gt;
            
            ☼ The Art of War,
Chapter 5, &amp;#x27;Defeating actively managed portfolios&amp;#x27;
            
        &lt;&#x2F;p&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;An investor has two types of accounts: tax-advantaged accounts and taxable
accounts. A tax-advantaged account lets you invest untaxed income or withdraw
untaxed gains. Here are some examples:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;invest untaxed income&lt;&#x2F;th&gt;&lt;th&gt;withdraw untaxed gains&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Traditional IRA&lt;&#x2F;td&gt;&lt;td&gt;Roth IRA&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Traditional 401(k)&lt;&#x2F;td&gt;&lt;td&gt;Roth 401(k)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;401(b)&lt;&#x2F;td&gt;&lt;td&gt;529 plan&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Health savings account&lt;&#x2F;td&gt;&lt;td&gt;Health savings account&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;…and more&lt;&#x2F;td&gt;&lt;td&gt;…and more&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;br&gt;
&lt;blockquote&gt;
&lt;p&gt;That’s right, the health savings account (should you qualify for one) has tax
advantages on the way in and on the way out, as well as during the ride itself
i.e. dividends. It’s often called a “triple tax-advantaged account.” Some US
states, ahem, &lt;em&gt;California and New Jersey&lt;&#x2F;em&gt;, do not recognize some of these
tax-advantages, so check to see how your state treats HSA contributions and
capital gains.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Put professionally, prioritize maxing out your tax-advantaged accounts. Put
accusingly, you might be sacrificing a lot of future gains by solely investing
in a fancy but nonetheless taxable account like Robinhood. Put bluntly, &lt;em&gt;do not
contribute a penny to your taxable account if you can instead contribute to a
tax-advantaged account!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Bonds are not very tax-efficient because they produce a lot of taxable
dividends. Try to hold your bonds in your 401(k) first, and then in your taxable
account if need be. Your Roth IRA and HSA are well-optimized for maximizing
growth, so I would make those my most aggressively allocated accounts with more
equities.&lt;&#x2F;p&gt;
&lt;p&gt;Deciding whether to prioritize placing your international stocks in a
tax-advantaged account or a taxable account is a personal decision that involves
a bunch of tax considerations. I personally hold all my international index
funds in a tax-deferred 401(k) because that is what works for my own tax
situation. But I emphasize that the tax implications of holding your
international index fund in a particular type of account is a very minor
optimization that doesn’t really affect you until you start holding a few
hundred thousand dollars in your portfolio.&lt;&#x2F;p&gt;
&lt;p&gt;So what exact things do you invest in? The answer depends on the type of
account. If you are in a tax-advantaged account, use mutual funds. If you are in
a taxable account, use ETFs. Be careful holding the exact same investments in
your tax-advantaged and taxable accounts in case you ever do something called
tax-loss harvesting.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s assume you are using Fidelity because they have awesome customer service
and great fund options:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Fidelity example&lt;&#x2F;th&gt;&lt;th&gt;Tax-advantaged account&lt;&#x2F;th&gt;&lt;th&gt;Taxable account&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;US index fund&lt;&#x2F;td&gt;&lt;td&gt;FZROX&lt;&#x2F;td&gt;&lt;td&gt;VTI&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;International index fund&lt;&#x2F;td&gt;&lt;td&gt;FZILX&lt;&#x2F;td&gt;&lt;td&gt;VXUS&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Bond index fund&lt;&#x2F;td&gt;&lt;td&gt;FXNAX&lt;&#x2F;td&gt;&lt;td&gt;BND&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;br&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;⚠ Warning&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Do not hold FZROX or FZILX in a taxable account. If you some day leave
Fidelity for another broker, then your shares of FZROX and FZILX will need to
be sold and you’ll pay taxes on your gains.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;…and for the sake of being a bit more thorough let’s assume you’re using
Vanguard (consider switching to Fidelity):&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Vanguard example&lt;&#x2F;th&gt;&lt;th&gt;Tax-advantaged account&lt;&#x2F;th&gt;&lt;th&gt;Taxable account&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;US index fund&lt;&#x2F;td&gt;&lt;td&gt;VTSAX&lt;&#x2F;td&gt;&lt;td&gt;VTI&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;International index fund&lt;&#x2F;td&gt;&lt;td&gt;VTIAX&lt;&#x2F;td&gt;&lt;td&gt;VXUS&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Bond index fund&lt;&#x2F;td&gt;&lt;td&gt;VBTLX&lt;&#x2F;td&gt;&lt;td&gt;BND&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;If you can’t directly pick these options because you can’t switch to these
brokerages or your employer’s 401(k) plan is restrictive, then try to pick a
similar substitute for each asset class. For instance, you might not have a US
total market index fund, but you’ll probably have access to at least an S&amp;amp;P 500
index fund.&lt;&#x2F;p&gt;
&lt;p&gt;For what its worth, this is a snapshot of my current portfolio allocation:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Portfolio à la Eric Cheng&lt;&#x2F;th&gt;&lt;th&gt;Taxable brokerage account&lt;&#x2F;th&gt;&lt;th&gt;Traditional 401(k)&lt;&#x2F;th&gt;&lt;th&gt;Roth IRA&lt;&#x2F;th&gt;&lt;th&gt;Health savings account&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;FZROX&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;60%&lt;&#x2F;td&gt;&lt;td&gt;60%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;FZILX&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;100%&lt;&#x2F;td&gt;&lt;td&gt;40%&lt;&#x2F;td&gt;&lt;td&gt;40%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;VTI&lt;&#x2F;td&gt;&lt;td&gt;100%&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;VXUS&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Don’t be fooled by the percentages – these percentages will change as my 401(k)
and brokerage accounts grow at different rates. Sixty-percent of this portfolio
is US total market index funds, with the remaining 40% in international total
market index funds – just like I described earlier. I just opt to hold my
international index funds in my 401(k).&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Not mentioned is the $300 I set aside to satisfy my self-destructive options
trading addiction.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;There’s some more nuance involving taxes and whatnot, but this is a pretty short
document because it only contains the exam answers. And as you can see, it is a
simple plan.&lt;&#x2F;p&gt;
&lt;p&gt;The long part is understanding &lt;em&gt;why&lt;&#x2F;em&gt; this simple plan is a winning
strategy.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#google&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#simplepath&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#bogleheads&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;badinvesting&quot;&gt;To be continued.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;google&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;For those who want to &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;T71ibcZAX3I&quot;&gt;listen&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;simplepath&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;For those who want to
&lt;a href=&quot;https:&#x2F;&#x2F;s1.papyruspub.com&#x2F;files&#x2F;demos&#x2F;products&#x2F;ebooks&#x2F;novels&#x2F;commercial-financial&#x2F;Preview-The-Simple-Path-to-Wealth-by-JL-Collins.pdf&quot;&gt;read&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;bogleheads&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;For those who want to &lt;a href=&quot;https:&#x2F;&#x2F;www.bogleheads.org&#x2F;wiki&#x2F;Getting_started&quot;&gt;read a bit
more&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Predicting the Russian endgame</title>
        <published>2022-10-12T00:00:00+00:00</published>
        <updated>2022-10-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/endgame/"/>
        <id>https://www.chengeric.com/endgame/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/endgame/">&lt;p&gt;Remember this?&lt;&#x2F;p&gt;







&lt;blockquote style=&quot;display:flex;padding:1em;&quot;&gt;
    &lt;div style=&quot;padding-right:1em;flex-shrink:0;&quot;&gt;
        &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;putin.b3710f57f65b2319.jpg&quot; style=&quot;border-radius:50%;&quot; &#x2F;&gt;
    &lt;&#x2F;div&gt;
    &lt;div&gt;
        &lt;p style=&quot;margin:0;&quot;&gt;
            &lt;b&gt;Vladimir
Putin&lt;&#x2F;b&gt;
            
            &lt;time class=&quot;timestamp&quot;&gt;
                ‧ 02&amp;#x2F;18&amp;#x2F;22
            &lt;&#x2F;time&gt;
            
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin-top:0;&quot;&gt;
            These military exercises, drills, are
purely defensive and are not a threat to any other country. They were planned
and all the objectives of these drills have been achieved.
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin:0;&quot; class=&quot;timestamp&quot;&gt;
            
            &lt;a href=https:&amp;#x2F;&amp;#x2F;news.sky.com&amp;#x2F;story&amp;#x2F;ukraine-crisis-putin-says-military-drills-purely-defensive-and-not-a-threat-as-western-leaders-warn-invasion-imminent-12545284&gt;☀ Six days before invading Ukraine&lt;&#x2F;a&gt;
            
        &lt;&#x2F;p&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;And then this?&lt;&#x2F;p&gt;







&lt;blockquote style=&quot;display:flex;padding:1em;&quot;&gt;
    &lt;div style=&quot;padding-right:1em;flex-shrink:0;&quot;&gt;
        &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;putin.b3710f57f65b2319.jpg&quot; style=&quot;border-radius:50%;&quot; &#x2F;&gt;
    &lt;&#x2F;div&gt;
    &lt;div&gt;
        &lt;p style=&quot;margin:0;&quot;&gt;
            &lt;b&gt;Vladimir Putin&lt;&#x2F;b&gt;
            
            &lt;time class=&quot;timestamp&quot;&gt;
                ‧ 02&amp;#x2F;24&amp;#x2F;22
            &lt;&#x2F;time&gt;
            
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin-top:0;&quot;&gt;
            Our plans do not include the occupation
of Ukrainian territories. We are not going to impose anything on anyone by
force.
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin:0;&quot; class=&quot;timestamp&quot;&gt;
            
            &lt;a href=https:&amp;#x2F;&amp;#x2F;edition.cnn.com&amp;#x2F;europe&amp;#x2F;live-news&amp;#x2F;ukraine-russia-news-02-23-22&amp;#x2F;h_cddb786d934a70cd52be9ab7ff68e1aa&gt;☀ Seven months before annexing 90,000 km²
of southeastern Ukraine&lt;&#x2F;a&gt;
            
        &lt;&#x2F;p&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;And this, too?&lt;&#x2F;p&gt;







&lt;blockquote style=&quot;display:flex;padding:1em;&quot;&gt;
    &lt;div style=&quot;padding-right:1em;flex-shrink:0;&quot;&gt;
        &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;putin.b3710f57f65b2319.jpg&quot; style=&quot;border-radius:50%;&quot; &#x2F;&gt;
    &lt;&#x2F;div&gt;
    &lt;div&gt;
        &lt;p style=&quot;margin:0;&quot;&gt;
            &lt;b&gt;Vladimir Putin&lt;&#x2F;b&gt;
            
            &lt;time class=&quot;timestamp&quot;&gt;
                ‧ 03&amp;#x2F;08&amp;#x2F;22
            &lt;&#x2F;time&gt;
            
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin-top:0;&quot;&gt;
            I emphasize that conscript soldiers are
not participating in hostilities and will not participate in them. And there
will be no additional call-up of reservists.
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin:0;&quot; class=&quot;timestamp&quot;&gt;
            
            &lt;a href=https:&amp;#x2F;&amp;#x2F;www.reuters.com&amp;#x2F;world&amp;#x2F;europe&amp;#x2F;putin-says-will-not-use-conscript-soldiers-ukraine-2022-03-07&amp;#x2F;&gt;☀ Six months before declaring partial mobilization&lt;&#x2F;a&gt;
            
        &lt;&#x2F;p&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Putin has an evident tendency of doing precisely what he says he will not. This
makes predicting the next stage of his war an interesting exercise.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; In no
particular order, let us list some noncredible predictions.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;striking-eu-gas-storage-facilities&quot;&gt;Striking EU gas storage facilities&lt;a class=&quot;zola-anchor&quot; href=&quot;#striking-eu-gas-storage-facilities&quot; aria-label=&quot;Anchor link for: striking-eu-gas-storage-facilities&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The suspense of slowly tearing off a bandage is arguably worse than ripping it
off in an instant. In much the same way, Russia halted its gas supply too early.
European countries were given a few months to scramble for alternatives and
prepare for the coming winter. Had Russia kept flicking the gas switch on and
off unpredictably – dragging the process on and causing a pointless debate
within the EU – it might have inflicted more pain when it shut off the gas
entirely by the winter.&lt;&#x2F;p&gt;
&lt;p&gt;To atone for this mistake, Russia has devised a scheme to destroy or hinder
European gas storage facilities. At some point of the winter, leaks start to
form along natural gas pipelines. There might be deliberate explosions involved.
The perpetrators are careful to hide their handiwork so Russia can claim
plausible deniability, but intentionally leave enough evidence to get the
implicit threat across.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;striking-eu-nuclear-power-plants&quot;&gt;Striking EU nuclear power plants&lt;a class=&quot;zola-anchor&quot; href=&quot;#striking-eu-nuclear-power-plants&quot; aria-label=&quot;Anchor link for: striking-eu-nuclear-power-plants&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;edYCtaNueQY?t=8&quot;&gt;I’ve seen this before.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-nuclear-weapons-against-ukraine&quot;&gt;Using nuclear weapons against Ukraine&lt;a class=&quot;zola-anchor&quot; href=&quot;#using-nuclear-weapons-against-ukraine&quot; aria-label=&quot;Anchor link for: using-nuclear-weapons-against-ukraine&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;With hope of defeating Ukraine waning and having already bottomed out its
diplomatic credibility, Russia launches nuclear missiles at Ukraine. They wait
until the coldest part of winter to maximize the pain.&lt;&#x2F;p&gt;







&lt;blockquote style=&quot;display:flex;padding:1em;&quot;&gt;
    &lt;div style=&quot;padding-right:1em;flex-shrink:0;&quot;&gt;
        &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;clown.75aac01d2b1ec5c3.jpg&quot; style=&quot;border-radius:50%;&quot; &#x2F;&gt;
    &lt;&#x2F;div&gt;
    &lt;div&gt;
        &lt;p style=&quot;margin:0;&quot;&gt;
            &lt;b&gt;Kremlin spokesperson&lt;&#x2F;b&gt;
            
            &lt;time class=&quot;timestamp&quot;&gt;
                ‧ 02&amp;#x2F;23&amp;#x2F;23
            &lt;&#x2F;time&gt;
            
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin-top:0;&quot;&gt;
            Earlier this morning, high-precision
nuclear weapons of the Russian Strategic Rocket Forces were deployed ... an
unavoidable action due to the continued defiance of the terrorist Kiev regime.
All military targets have been completely destroyed in accordance with tactical
objectives.
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin:0;&quot; class=&quot;timestamp&quot;&gt;
            
            ☼ Hypothetical scenario
            
        &lt;&#x2F;p&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Various Western pundits had entertained the notion of Russia using nuclear
weapons in Ukraine to their superiors, but few had truly believed in this
outcome themselves. Perhaps Russia would detonate a smaller sub-megaton nuclear
device high up in Ukrainian airspace or deep below the Black Sea as a gesture of
intimidation, but that would be stretching it. After all, Russia has a tendency
to do the opposite of what they say, so repeated nuclear threats would surely
only be a bluff.&lt;&#x2F;p&gt;
&lt;p&gt;But such predictions have lost their meaning. Ukrainians enter their bomb
shelters preparing to sit through a conventional air raid, but are instead met
with a nuclear blast. Millions of Ukrainians are killed; the Kremlin shifts the
focus of the war from absorbing Ukraine to crush the country beyond any hope of
Western-led recovery.&lt;&#x2F;p&gt;
&lt;p&gt;The shattering of the nuclear taboo is deafening in the West. To Russia’s more
sympathetic ears in Asia and the Middle East, news of the blasts will be
downplayed, denied, retroactively justified, or outright censored.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-nuclear-weapons-against-yourself&quot;&gt;Using nuclear weapons against yourself&lt;a class=&quot;zola-anchor&quot; href=&quot;#using-nuclear-weapons-against-yourself&quot; aria-label=&quot;Anchor link for: using-nuclear-weapons-against-yourself&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Unwilling to risk the consequences of the above scenario, Russia instead decides
to lob a nuclear cruise missile at one of its own peripheral cities. Russian
state media blames Ukraine, fabricating a story about how Ukraine secretly
resurrected its nuclear weapons program under the guidance of the United States.&lt;&#x2F;p&gt;
&lt;p&gt;Some Russians find the state narrative unconvincing and flee the country; some
are more receptive to the manufactured consent. Putin orders another wave of
mobilization.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;electing-useful-idiots-abroad&quot;&gt;Electing useful idiots abroad&lt;a class=&quot;zola-anchor&quot; href=&quot;#electing-useful-idiots-abroad&quot; aria-label=&quot;Anchor link for: electing-useful-idiots-abroad&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Unfortunately for Putin, the U.S. presidential election is not for another two
years. Had it invaded during an election year, Russia could ardently promote
Trump or another Russian sympathizer into the White House.&lt;&#x2F;p&gt;
&lt;p&gt;Still, Russia desperately needs to convince the world that it is willing to
outlast Western support. They can achieve this by portraying the conflict as
being too muddy to distinguish good from evil, too costly to continue paying
for, and too irrelevant when compared to the domestic problems at home.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;selling-gazprom-stake-to-china&quot;&gt;Selling Gazprom stake to China&lt;a class=&quot;zola-anchor&quot; href=&quot;#selling-gazprom-stake-to-china&quot; aria-label=&quot;Anchor link for: selling-gazprom-stake-to-china&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Having realized the war can remain stagnant longer than the Russian economy can
remain afloat, Russia reluctantly offers to sell its state petroleum interests
to the highest Chinese bidder. China wants to appear neutral in this conflict,
but the offer is too good to pass up.&lt;&#x2F;p&gt;
&lt;p&gt;To make such a transaction even remotely tenable, Putin orders a mass purge of
the dissenting oligarchs and offers to split the prize among a few trusted
insiders within the military and his cabinet. The estates of the purged are
liquidated for the war effort.&lt;&#x2F;p&gt;
&lt;p&gt;Russia, with its new injection of cash, gets to continue fighting in Ukraine.
Unfortunately, rampant corruption within the military and horrific combat
casualty rates result in this final sugar high being less helpful than imagined.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;attacking-nato&quot;&gt;Attacking NATO&lt;a class=&quot;zola-anchor&quot; href=&quot;#attacking-nato&quot; aria-label=&quot;Anchor link for: attacking-nato&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;







&lt;blockquote style=&quot;display:flex;padding:1em;&quot;&gt;
    &lt;div style=&quot;padding-right:1em;flex-shrink:0;&quot;&gt;
        &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;kalev.5d3b5bfe9a94ba32.jpg&quot; style=&quot;border-radius:50%;&quot; &#x2F;&gt;
    &lt;&#x2F;div&gt;
    &lt;div&gt;
        &lt;p style=&quot;margin:0;&quot;&gt;
            &lt;b&gt;Kalev Stoicescu&lt;&#x2F;b&gt;
            
            &lt;time class=&quot;timestamp&quot;&gt;
                ‧ 07&amp;#x2F;14&amp;#x2F;22
            &lt;&#x2F;time&gt;
            
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin-top:0;&quot;&gt;
            Many of Russia’s recent actions have
achieved the exact opposite of what they were intended to do because of Moscow’s
faulty understanding of events and processes in the outside world. For example,
Russia makes military threats and launches military action in order to dissuade
neighbours from joining NATO – with the only result being to demonstrate to
those neighbours precisely why they need to join.
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin:0;&quot; class=&quot;timestamp&quot;&gt;
            
            &lt;a href=https:&amp;#x2F;&amp;#x2F;www.chathamhouse.org&amp;#x2F;2022&amp;#x2F;06&amp;#x2F;myths-and-misconceptions-around-russian-military-intent&amp;#x2F;myth-3-russia-wouldnt-attack-nato&gt;☀ Myths and misconceptions around Russian military
intent&lt;&#x2F;a&gt;
            
        &lt;&#x2F;p&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Russia hopes to distract the West from Ukraine, and somehow arrives at the
conclusion that it must try to beat up a Baltic country.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implementing-a-scorched-earth-policy&quot;&gt;Implementing a scorched earth policy&lt;a class=&quot;zola-anchor&quot; href=&quot;#implementing-a-scorched-earth-policy&quot; aria-label=&quot;Anchor link for: implementing-a-scorched-earth-policy&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;







&lt;blockquote style=&quot;display:flex;padding:1em;&quot;&gt;
    &lt;div style=&quot;padding-right:1em;flex-shrink:0;&quot;&gt;
        &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;russia.e46b8088696f9f9f.jpg&quot; style=&quot;border-radius:50%;&quot; &#x2F;&gt;
    &lt;&#x2F;div&gt;
    &lt;div&gt;
        &lt;p style=&quot;margin:0;&quot;&gt;
            &lt;b&gt;FSB defector&lt;&#x2F;b&gt;
            
            &lt;time class=&quot;timestamp&quot;&gt;
                ‧ 07&amp;#x2F;07&amp;#x2F;34
            &lt;&#x2F;time&gt;
            
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin-top:0;&quot;&gt;
            The whole Donbas thing was just a
gimmick. The true objective was to deny Ukraine from wrongly developing land
that we rightfully stole.
        &lt;&#x2F;p&gt;
        &lt;p style=&quot;margin:0;&quot; class=&quot;timestamp&quot;&gt;
            
            ☼ Reflecting on Russia&amp;#x27;s ultimate defeat in Ukraine
            
        &lt;&#x2F;p&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;I make this all up as I doomscroll or shower.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Don’t get me wrong: in an ideal timeline, Ukraine continues to rout
Russian forces back to pre-war borders, the West arms Ukraine with the
longer-range weapons it needs to secure its advances, and Putin has the
bitter but obvious realization that sacrificing a generation of economic
development and imperiling millions of ill-equipped Russians is not worth
the risk to his regime.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Such an intricate and coordinated attack requires an extreme level of
operational competence and security. So I would suspect it is impossible for
Russia to conduct.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Using Wi-Fi to track gym occupancy</title>
        <published>2022-08-26T00:00:00+00:00</published>
        <updated>2022-08-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/gym/"/>
        <id>https://www.chengeric.com/gym/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/gym/">&lt;p&gt;A busy gym is a motivating environment, but a very busy gym is a frustrating
problem. When I returned to campus for my senior year, I discovered
that the school gym had fallen into this latter category.&lt;&#x2F;p&gt;
&lt;p&gt;For one thing, it closed a few hours earlier in the evening. And it was now much
busier overall compared to before the pandemic. I was now spending a lot of time
waiting for equipment – either because it was already occupied, or because I
was sharing it.&lt;&#x2F;p&gt;
&lt;p&gt;The solution to this problem is supposedly simple: if you don’t want to wait for
things in the gym, then you must work out when the gym isn’t busy.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;So I’ll just have to work out at a weird time nobody else would think of!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Well, this strategy often backfired: my perception of the gym’s busiest hours
was far too predictable, and the gym’s busiest hours on any given day was far
too unpredictable. I would like to think that my planning was often so
predictable that a bunch of people had the same idea, and we ironically ended up
converging at the same time to work out anyways.&lt;&#x2F;p&gt;
&lt;p&gt;What could the gym do to solve these problems? There are some naïve, blunt
approaches that technically work but actually suck. Let’s examine and eliminate
these options:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The gym operates like an art gallery, drastically lowering the maximum
occupancy limit and refusing to admit anybody beyond the limit.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The gym operates like a movie theater, assigning students “tickets” that
permit entry during a specific time slot.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The gym operates like a nightclub, employing a student-bouncer to only let in
those who workout quickly and to kick out laggards.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The gym operates like a taxi company, selling a fixed quantity of transferable
gym permits to constrain the gym population.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The gym operates like a medieval craft guild, offering the exclusivity and
prestige of a gym membership to select Dean’s list recipients who, in return,
donate a hefty sum to the university.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;But I digress. The point is that the gym should be a freely available resource,
and people should be empowered to make smarter decisions about when to go.
Unfortunately, there isn’t a way at Carnegie Mellon to know if the gym is busy
unless somebody is there to tell you, or you observe the gym yourself. If there
was a 24&#x2F;7 livestream of the gym, then it would be easy to remotely check if the
gym is busy or not with just a glance. But there are glaring security and
privacy sacrifices with this livestream proposal, so we need to think of other
methods.&lt;&#x2F;p&gt;
&lt;p&gt;If we distill this problem, then we understand that the gym’s busyness is
tightly correlated with a single metric: the number of people in the gym. So if
we can count the people in the gym, then we can infer the probability of having
to wait for equipment.&lt;&#x2F;p&gt;
&lt;p&gt;So with our goal of counting people established, we can consider many technical
approaches:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;There’s always a student stationed in the gym as a desk
attendant. We can task this student with digitally recording the current gym
population into as people entered and exited. But doing this for hours is
extremely tedious and liable to inaccuracy or misreporting. This kind of brute
force approach is inappropriate for such a readily automated task.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Install special cameras in the gym that use a sophisticated AI algorithm to
recognize and count people in a privacy-friendly manner. But these cameras are
generally incredibly expensive and often charge a monthly subscription fee.
Also consider the difficulty of installation — how would these cameras be
supplied with power and an Internet connection?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Mount sensors on top of doors to track the number of people entering and
exiting the gym. But this suffers from the same problems listed above
regarding cameras.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Count the taps on the ID readers outside the gym doors. But without additional
equipment we would have no idea when somebody leaves the gym, or if somebody
enters the gym without tapping (such as when somebody holds the door open for
them).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Measure the airborne carbon dioxide concentration to estimate the number of
people inside. I’m skeptical this would work well because physical
exertion can make a human’s carbon dioxide output highly variable.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;But there is a far cheaper approach we can use. We can make two specific and
critical assumptions about our situation that simplifies the problem greatly.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s illustrate this from a CMU perspective:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;A CMU student carries their phone in a pocket or bag. This phone is connected
to the campus Wi-Fi network.&lt;&#x2F;li&gt;
&lt;li&gt;The CMU student enters the gym. The phone’s Wi-Fi antenna roams to one of the
wireless access points (WAPs)&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; in the gym.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Therefore, if you know the number of clients connected to the WAPs in the gym,
you can approximate the number of people in the gym.&lt;&#x2F;p&gt;
&lt;p&gt;The number of clients connected to a particular WAPs is most likely &lt;a href=&quot;https:&#x2F;&#x2F;www.arubanetworks.com&#x2F;techdocs&#x2F;Instant_41_Mobile&#x2F;Advanced&#x2F;Content&#x2F;CLI_commands&#x2F;show_clients.htm&quot;&gt;already
available&lt;&#x2F;a&gt;
to CMU network admins. Getting this number published as an API is the hard part.
This step will probably require a few emails and meetings with university
administrators. Once you have client population figures, the fun begins.&lt;&#x2F;p&gt;
&lt;p&gt;You could browse to a website like cmugyms.com&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; and see a live figure of
estimated people in the gym. As people workout en masse, the number of devices
connected to the gym’s WAPs surges. And as they leave, the number of devices
decreases. We would need to calibrate the initial count by observing the number
of persistent devices connected to gym WAPs, such as printers or office
computers, that do not belong to gymgoers. We would also need to account for
some individuals carrying more than a single Wi-Fi device into the gym: people
not only carry their phones, but also their backpacks containing laptops or
tablets. The average number of Wi-Fi devices somebody brings into the gym is
likely greater than one.&lt;&#x2F;p&gt;
&lt;p&gt;The advantage of this ‘Wi-Fi heuristic’ is how technically simple it is. This not
only makes it cheap, but also universal. This method could work at any
institution and at any specific location with WAPs nearby, like dining halls,
libraries, or lounges.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, I would have continued on with a proof-of-concept. But I am sadly
forced to leave this proof as an exercise for the reader.&lt;&#x2F;p&gt;
&lt;p&gt;You see, I unfortunately thought of this idea about a week before I graduated
this past May. But fortunately for you, this idea remains plausible and awaits a
proper implementation.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;LjbI7pPnVYw&quot;&gt;youtu.be&#x2F;LjbI7pPnVYw&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;cmugyms.com could be for tracking campus gyms as
&lt;a href=&quot;https:&#x2F;&#x2F;cmueats.com&quot;&gt;cmueats.com&lt;&#x2F;a&gt; is for tracking campus food&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>chengeric.com, not ericcheng.com</title>
        <published>2022-08-18T00:00:00+00:00</published>
        <updated>2022-08-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/chengeric/"/>
        <id>https://www.chengeric.com/chengeric/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/chengeric/">&lt;p&gt;&lt;strong&gt;TL;DR:&lt;&#x2F;strong&gt; ericcheng.com was too expensive and I didn’t want a used domain.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Before I &lt;a href=&quot;&#x2F;zola&quot;&gt;built&lt;&#x2F;a&gt; this website, I had to think about which domain name I
would pick.&lt;&#x2F;p&gt;
&lt;p&gt;This decision was not very straightforward. I knew I wanted a &lt;em&gt;.com&lt;&#x2F;em&gt; domain as
close as possible to my name, &lt;em&gt;Eric Cheng&lt;&#x2F;em&gt;. But the issue is that &lt;em&gt;Eric Cheng&lt;&#x2F;em&gt;
is a fairly common name, and there’s a surprisingly disproportionate number of
people named Eric Cheng already on the internet.&lt;&#x2F;p&gt;
&lt;p&gt;I spent a while checking various permutations of &lt;em&gt;eric&lt;&#x2F;em&gt;, &lt;em&gt;cheng&lt;&#x2F;em&gt;, &lt;em&gt;.com&lt;&#x2F;em&gt;, and
some wildcard characters. Here are some of the interesting websites I found
along the way.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;eric.com&lt;&#x2F;em&gt; &lt;a href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20180808061325&#x2F;http:&#x2F;&#x2F;eric.com&#x2F;&quot;&gt;was&lt;&#x2F;a&gt; a
weird but charming Internet monument dedicated to notable Erics. From what I can
gather from &lt;a href=&quot;https:&#x2F;&#x2F;lookup.icann.org&#x2F;en&#x2F;lookup&quot;&gt;ICANN&lt;&#x2F;a&gt; and the Internet
Archive, a man named Eric Elgar purchased the domain in 1994. We can even see
how it looked as early as
&lt;a href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;19961104053055&#x2F;http:&#x2F;&#x2F;www.eric.com&#x2F;&quot;&gt;1996&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;

































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;ericdotcom.48d04cc36999d565.jpg&quot;
        class=&quot;&quot; alt=&quot;eric.com&quot;  width=677 &#x2F;&gt;
    &lt;figcaption&gt;eric.com in its prime&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The website remained practically unchanged from 2000 to 2020, and quietly went
offline at some point in early 2020. Today, &lt;a href=&quot;https:&#x2F;&#x2F;eric.com&quot;&gt;eric.com&lt;&#x2F;a&gt; is
listed for sale.&lt;&#x2F;p&gt;

































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;ericdotcomtoday.cbfb041b02865a2c.jpg&quot;
        class=&quot;&quot; alt=&quot;eric.com
today&quot;  width=677 &#x2F;&gt;
    &lt;figcaption&gt;eric.com ended at some point during the early phase of the
COVID-19 pandemic&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;It’s sad to see zany old websites like &lt;em&gt;eric.com&lt;&#x2F;em&gt; suddenly vanish. Websites like
these make me feel nostalgic for an era of a simpler Internet that I can only
faintly remember as a zoomer — a time before I understood how search engines
worked and I discovered websites by typing random URLs into Internet Explorer.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;cheng.com&quot;&gt;cheng.com&lt;&#x2F;a&gt; was registered by an MIT student or faculty
member in 1995. It was an academic directory before becoming a redirect to a
family’s photo album. Then the website metamorphosed into its ultimate form: a
broken link which still stands to this day.&lt;&#x2F;p&gt;

































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;error.2a64e1b9862be5a1.jpg&quot;
        class=&quot;&quot; alt=&quot;eric.com&quot;  width=677 &#x2F;&gt;
    &lt;figcaption&gt;cheng.com in 2022&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;I knew the odds of securing &lt;em&gt;eric.com&lt;&#x2F;em&gt; or &lt;em&gt;cheng.com&lt;&#x2F;em&gt; was practically zero. It
still felt good to be an Internet archaeologist.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;ericcheng.com&quot;&gt;ericcheng.com&lt;&#x2F;a&gt; was a mysterious blank page. Today, it
still remains a blank page.&lt;&#x2F;p&gt;






























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;ericchengdotcomtoday.bfa5de821bafb9b9.jpg&quot;
        class=&quot;&quot; alt=&quot;ericcheng.com today&quot;  width=977 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;But the plot thickens. If you visit Google Domains, you actually can buy
ericcheng.com for the absolute bargain bin price of $3,150 + $12&#x2F;year. GoDaddy
charges a few hundred more for some reason.&lt;&#x2F;p&gt;

































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;ericchengdotcom.5e0f6e8eb25f5a01.jpg&quot;
        class=&quot;&quot; alt=&quot;ericcheng.com
for sale&quot;  width=677 &#x2F;&gt;
    &lt;figcaption&gt;What a steal!&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Seeing ericcheng.com was available for such a steep price prompted a number of
questions in my mind.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Why is it so expensive?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;What happened to the owner?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;What was the website for originally?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Would somebody ever buy it in the future?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Although we may never know the true answer to these questions, and although
ericcheng.com is still a blank page, we can still piece some information
together. &lt;a href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20040730095743&#x2F;http:&#x2F;&#x2F;www.ericcheng.com&#x2F;&quot;&gt;An archived version of
ericcheng.com&lt;&#x2F;a&gt;
reveals that it was once a family photo album, presumably of a man named Eric
Cheng living in Hong Kong.&lt;&#x2F;p&gt;

































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;ericchengphotos.8033ae960e28f0d5.jpg&quot;
        class=&quot;&quot; alt=&quot;ericcheng.com
back then&quot;  width=677 &#x2F;&gt;
    &lt;figcaption&gt;ericcheng.com in July 2004&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;ericchenglogin.e01f72c4b823fc6b.jpg&quot;
        class=&quot;&quot; alt=&quot;ericcheng.com
back then&quot;  width=677 &#x2F;&gt;
    &lt;figcaption&gt;ericcheng.com in November 2005. This is the last recorded
version of the website; the next snapshot takes place eight years later in 2013,
but it&#x27;s only the blank page onwards.&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;I was originally frustrated to see that ericcheng.com was practically
unavailable. I even contemplated if the high price was worth it, since it meant
securing a domain that I could potentially use for decades. If the Internet was
still running on URLs for another 50 years, then I could probably justify this
temptation by mentally amortizing the cost over the course of half a century.
But then I changed my mind for two main reasons.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It just didn’t feel right. &lt;em&gt;ericcheng.com&lt;&#x2F;em&gt; once belonged to another Eric
Cheng. If I were to buy it and point the domain name to my own website, I
would be paving over this guy’s legacy. Even if &lt;em&gt;ericcheng.com&lt;&#x2F;em&gt; is just a
blank white screen today, the mystery of it still makes you briefly wonder
about the owner.&lt;&#x2F;p&gt;
&lt;p&gt;Buying a personal domain name such as &lt;em&gt;ericcheng.com&lt;&#x2F;em&gt; isn’t like passing a
baton from one Eric Cheng to the next. The Internet doesn’t work like that.
When a restaurant, a factory, or a shopping mall is renovated or even
outright abandoned, you can still somewhat recognize the appearance of the
building as it once stood and guess at its original function. But websites
are much more impermanent; when they are renovated or abandoned, the
original is gone for good.&lt;&#x2F;p&gt;
&lt;p&gt;If I bought &lt;em&gt;ericcheng.com&lt;&#x2F;em&gt;, you would have to dive into the &lt;a href=&quot;https:&#x2F;&#x2F;archive.org&quot;&gt;Internet
Archive&lt;&#x2F;a&gt; to discover the domain was not mine
originally. And Internet Archive isn’t perfect; it’s often unable to
retrieve the complete version of a past website. Of course, domain names
can’t be perpetually tied to an individual, but there were plenty of other
domain names that I could instead select to spare this guy from being wiped
completely.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&amp;gt;$3,000 is way beyond what a student should spend on their personal domain
name.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;With the obvious candidates unavailable or eliminated, I continued my search. I
discovered more modern websites owned by other people named Eric Cheng.&lt;&#x2F;p&gt;
&lt;p&gt;With great interest, I noted the domain name that each Eric picked.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; With
great fascination, I learned a bit about each Eric’s life. Some were engineers,
some were artists, some were deeply interested in photography, but everybody
used their website to discuss their skills and lives. I felt like I was looking
at alternate versions of myself.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually, I found that &lt;em&gt;chengeric.com&lt;&#x2F;em&gt; was available and completely unused.
The swapped order of my first and last names could be interpreted as just a
little quirk, or a nod towards my Asian background. I bought the domain in 2018
and have made &lt;em&gt;chengeric.com&lt;&#x2F;em&gt; my corner of the Internet since.&lt;&#x2F;p&gt;
&lt;p&gt;Whenever I find a new Eric Cheng website sprouting out of search engine
obscurity, I add it to the &lt;a href=&quot;&#x2F;about#honorable-mentions&quot;&gt;honorable mentions&lt;&#x2F;a&gt; list
on this website. I’ve been doing this since 2019. Sometimes I wonder how long
I’ll continue.&lt;&#x2F;p&gt;
&lt;p&gt;What gives me encouragement and amusement is knowing that every new Eric Cheng
seeking to buy his own domain name begins by first discovering how expensive
&lt;em&gt;ericcheng.com&lt;&#x2F;em&gt; is. His journey will be incrementally more difficult than that
of the previous Eric Cheng as fewer domains are now available. He will perhaps
wonder the same things and contemplate the same choices as me.&lt;&#x2F;p&gt;
&lt;p&gt;It is truly an unspoken solidarity spanning land, time, but not name.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thanks for stopping by my corner of the internet today, weary traveler. Feel
free to rest here before you venture to the other Eric Cheng websites.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;.&#x2F;campfire.gif&quot; alt=&quot;campfire&quot;
style=&quot;width:99.9%;border-radius:8px;margin-bottom:1em;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Regrettably, some of the modern Eric Chengs purchased domains names that
once belonged to other Eric Chengs twenty or so years ago. I won’t judge
them for it — finding a domain name is ultimately a personal decision and
isn’t easy. However, this makes it very hard to count all the unique Eric
Chengs that have ever had their own domain name.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Command line tricks for college</title>
        <published>2022-04-24T00:00:00+00:00</published>
        <updated>2022-04-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/cli/"/>
        <id>https://www.chengeric.com/cli/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/cli/">&lt;p&gt;The command line can save you a lot of time in college. Here are some common
problems outside of a computer science course that powerful CLI tools can
tackle.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;All of the tools I’m linking here can be easily installed via Homebrew on
macOS. Before I started using a MacBook, I used these same tools on Arch
Linux.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;fix-bad-pdfs&quot;&gt;Fix bad PDFs&lt;a class=&quot;zola-anchor&quot; href=&quot;#fix-bad-pdfs&quot; aria-label=&quot;Anchor link for: fix-bad-pdfs&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;




























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;badpdf.50ec58b1247fd581.jpg&quot;
        class=&quot;&quot; alt=&quot;badpdf&quot;  width=977 &#x2F;&gt;
    &lt;figcaption&gt;What your Wednesday night reading looks like&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;On countless occasions I had to deal with PDFs whose pages were skewed, grainy,
rotated, and&#x2F;or not Ctrl-F friendly. You can rotate the PDF in the browser, but
what if the pages are rotated in all sorts of directions? What if you want to
search for text in the document, but you can’t? When trying to fix these issues,
a lot of people will head for Adobe Acrobat. There’s nothing inherently wrong
about this, but Acrobat isn’t always available with your university’s software
license program, nor is it particularly fast or intuitive.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ocrmypdf&#x2F;OCRmyPDF&quot;&gt;&lt;code&gt;ocrmypdf&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; adds an OCR text layer to
PDFs that will let you search, highlight, and copy-and-paste content as you
would expect from a good PDF. It can also de-skew and rotate your pages into an
upright position.&lt;&#x2F;p&gt;
&lt;p&gt;This command takes &lt;code&gt;bad.pdf&lt;&#x2F;code&gt; and produces &lt;code&gt;good.pdf&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ ocrmypdf --rotate-pages --deskew bad.pdf good.pdf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;




























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;goodpdf.5af948a7c8b9faaa.jpg&quot;
        class=&quot;&quot; alt=&quot;goodpdf&quot;  width=977 &#x2F;&gt;
    &lt;figcaption&gt;Now I can highlight and search for text!&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;h2 id=&quot;combine-pdfs&quot;&gt;Combine PDFs&lt;a class=&quot;zola-anchor&quot; href=&quot;#combine-pdfs&quot; aria-label=&quot;Anchor link for: combine-pdfs&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mtgrosser&#x2F;pdfunite&quot;&gt;&lt;code&gt;pdfunite&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; combines multiple PDFs into
a single file. This is particularly useful when you’re reviewing lecture slides
in preparation for an upcoming exam, and don’t want to juggle browser tabs.&lt;&#x2F;p&gt;
&lt;p&gt;For instance, let’s say I have six PDFs that each cover a single chapter’s worth
of content. I’ll combine them like so:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ pdfunite 1.pdf 2.pdf 3.pdf 4.pdf 5.pdf 6.pdf review.pdf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;…and just open up &lt;code&gt;review.pdf&lt;&#x2F;code&gt; in my browser to study.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;turn-stuff-into-pdfs&quot;&gt;Turn stuff into PDFs&lt;a class=&quot;zola-anchor&quot; href=&quot;#turn-stuff-into-pdfs&quot; aria-label=&quot;Anchor link for: turn-stuff-into-pdfs&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Have you ever expected to be provided with a PDF for something, only to discover
that your professor has instead issued you a PowerPoint &lt;code&gt;.pptx&lt;&#x2F;code&gt; or Word &lt;code&gt;.docx&lt;&#x2F;code&gt;
file? Avoid having to wait for those Office splash screens and just convert
those documents into a PDF.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ soffice --headless --convert-to pdf lecture-notes.pptx
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;You’ll need to install LibreOffice
(&lt;a href=&quot;https:&#x2F;&#x2F;formulae.brew.sh&#x2F;cask&#x2F;libreoffice&quot;&gt;Homebrew&lt;&#x2F;a&gt;) to use &lt;code&gt;soffice&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;transfer-stuff-between-computers&quot;&gt;Transfer stuff between computers&lt;a class=&quot;zola-anchor&quot; href=&quot;#transfer-stuff-between-computers&quot; aria-label=&quot;Anchor link for: transfer-stuff-between-computers&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;schollz&#x2F;croc&quot;&gt;&lt;code&gt;croc&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is a tool that lets you send files to
any other computer that has &lt;code&gt;croc&lt;&#x2F;code&gt; installed.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#wormhole&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; All your recipient
needs to do is type in a specific phrase from their terminal to receive your
file. This is vastly easier and faster than using &lt;code&gt;ssh&lt;&#x2F;code&gt; or &lt;code&gt;rsync&lt;&#x2F;code&gt;, because such
tools become largely obsolete if the clients are on separate networks. Plus,
&lt;code&gt;croc&lt;&#x2F;code&gt; is also encrypted so you can rely on the same sense of security. You can
think of &lt;code&gt;croc&lt;&#x2F;code&gt; like a kind of cross-platform AirDrop built for the command
line.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-you-do-to-send&quot;&gt;What you do to send&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-you-do-to-send&quot; aria-label=&quot;Anchor link for: what-you-do-to-send&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ croc send cat.jpg
&lt;&#x2F;span&gt;&lt;span&gt;Sending &amp;#39;cat.jpg&amp;#39; (1.1 kB)
&lt;&#x2F;span&gt;&lt;span&gt;Code is: 3750-alibi-memo-local
&lt;&#x2F;span&gt;&lt;span&gt;On the other computer run
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;croc 3750-alibi-memo-local
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Sending (-&amp;gt;123.123.123.123:56112)
&lt;&#x2F;span&gt;&lt;span&gt; 100% |████████████████████| (1.1&#x2F;1.1 kB, 926.589 kB&#x2F;s)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;what-your-friend-does-to-receive&quot;&gt;What your friend does to receive&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-your-friend-does-to-receive&quot; aria-label=&quot;Anchor link for: what-your-friend-does-to-receive&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ croc 3750-alibi-memo-local
&lt;&#x2F;span&gt;&lt;span&gt;Accept &amp;#39;cat.jpg&amp;#39; (1.1 kB)? (Y&#x2F;n)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Receiving (&amp;lt;-321.321.321.321:58681)
&lt;&#x2F;span&gt;&lt;span&gt; 100% |████████████████████| (1.1&#x2F;1.1 kB, 21.985 kB&#x2F;s)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;delete-stuff-safely&quot;&gt;Delete stuff safely&lt;a class=&quot;zola-anchor&quot; href=&quot;#delete-stuff-safely&quot; aria-label=&quot;Anchor link for: delete-stuff-safely&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;We all invariably use &lt;code&gt;rm -rf&lt;&#x2F;code&gt; recklessly sometimes. Because of the inherent
danger of wielding &lt;code&gt;rm&lt;&#x2F;code&gt; in situations where you only really mean to delete a
small image or text file, it is far safer to use &lt;code&gt;trash-cli&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ trash temp.txt 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this example, &lt;code&gt;temp.txt&lt;&#x2F;code&gt; will be moved to trash, where you can always restore
it later if needed.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;See &lt;a href=&quot;https:&#x2F;&#x2F;formulae.brew.sh&#x2F;formula&#x2F;trash-cli&quot;&gt;Homebrew&lt;&#x2F;a&gt; or
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;andreafrancia&#x2F;trash-cli&quot;&gt;Linux&lt;&#x2F;a&gt; links for installation
instructions&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;pretend-to-be-busy&quot;&gt;Pretend to be busy&lt;a class=&quot;zola-anchor&quot; href=&quot;#pretend-to-be-busy&quot; aria-label=&quot;Anchor link for: pretend-to-be-busy&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;svenstaro&#x2F;genact&quot;&gt;&lt;code&gt;genact&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is for you. This hasn’t really
saved me time; it’s just for fun.&lt;&#x2F;p&gt;




























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;terminal1.4fa36998e60446c7.jpg&quot;
        class=&quot;&quot; alt=&quot;genact&quot;  width=787 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;



























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;terminal2.727914a38f9ba254.jpg&quot;
        class=&quot;&quot; alt=&quot;genact&quot;  width=787 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;



























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;terminal3.5d1da61fe094b143.jpg&quot;
        class=&quot;&quot; alt=&quot;genact&quot;  width=787 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;wormhole&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;You might have heard of croc’s better known alternative &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;magic-wormhole&#x2F;magic-wormhole&quot;&gt;Magic Wormhole&lt;&#x2F;a&gt;. I used to use Magic Wormhole instead of croc, but I found that croc was overall the better choice. Croc is written in Go, so it doesn’t have any Python dependencies like Magic Wormhole. It supports pause&#x2F;resume, folder transfers without first converting the folder into a zipfile, and relay-less transfers. I also find that croc is generally faster on my machines.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Moving this website to Zola</title>
        <published>2022-04-15T00:00:00+00:00</published>
        <updated>2022-04-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/zola/"/>
        <id>https://www.chengeric.com/zola/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/zola/">&lt;p&gt;This is the third generation of my website. It is currently built with
&lt;a href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt;, an &lt;a href=&quot;https:&#x2F;&#x2F;www.chengeric.com&#x2F;zola&#x2F;#generation-3-0-zola&quot;&gt;excellent&lt;&#x2F;a&gt; static
site generator written in Rust.&lt;&#x2F;p&gt;
&lt;p&gt;The previous generation of this website used
&lt;a href=&quot;https:&#x2F;&#x2F;www.gatsbyjs.com&#x2F;&quot;&gt;Gatsby&lt;&#x2F;a&gt;, a popular static site generator combining
React with GraphQL. Using Gatsby was a poor decision. Gatsby has its place, but
there’s no need to use it for a small personal blog unless you really want to
learn how to use Gatsby for a larger project. I’m not a purist who would eschew
something simply because it is complicated, because I understand that a complex
problem will sometimes require a complex solution.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; But using Gatsby
inappropriately for websites like this is a choice that novices are ill-prepared
to build and more importantly, maintain.&lt;&#x2F;p&gt;
&lt;p&gt;Gatsby is fundamentally designed for big projects. The design patterns that it
encourages are an &lt;a href=&quot;https:&#x2F;&#x2F;cra.mr&#x2F;an-honest-review-of-gatsby&#x2F;&quot;&gt;over-engineered
obstacle&lt;&#x2F;a&gt; for the individual rather
than a useful tool. The performance it touts also aren’t discernible unless you
have some &lt;em&gt;really beefy&lt;&#x2F;em&gt; projects.&lt;&#x2F;p&gt;
&lt;p&gt;New developers who recently learn about the latest innovations in React or Node
fall prey into becoming very impressionable. I can attest to this, because I was
once this exact person, and this mindset drove me towards Gatsby.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I suppose it is tempting, if the only tool you have is a hammer, to treat
everything as if it were a nail.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;– &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Law_of_the_instrument&quot;&gt;Abraham Maslow&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;But there was a time before I knew what Gatsby, static site generators, or React
was. My first websites in high school were very basic — I knew no way to
handle automation or templating whatsoever, and thus much of my time was spent
copying and pasting chunks of HTML and CSS boilerplate code. If I modified the
navigation bar on my website, then I would have to repeat that edit on every
file containing the navigation bar code.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually, a friend of mine introduced me to &lt;a href=&quot;https:&#x2F;&#x2F;ejs.co&#x2F;&quot;&gt;Embedded
Javascript&lt;&#x2F;a&gt;, which was a game-changer because it enabled me to
template large chunks of HTML. I now had my first taste of the Node ecosystem
and could begin experimenting with packages and their functionality.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;generation-1-0-ejs&quot;&gt;Generation 1.0 – EJS&lt;a class=&quot;zola-anchor&quot; href=&quot;#generation-1-0-ejs&quot; aria-label=&quot;Anchor link for: generation-1-0-ejs&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I bought the domain &lt;code&gt;chengeric.com&lt;&#x2F;code&gt; during my senior year of high school. The
first incarnation of this website lived on a Digital Ocean droplet running an
Express server, which in turn hosted my little EJS website.&lt;&#x2F;p&gt;






























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;gen1.1e9e218a16485d09.jpg&quot;
        class=&quot;&quot; alt=&quot;First generation chengeric.com&quot;  width=977 &#x2F;&gt;
    &lt;figcaption&gt;The first version of this website back in the
summer of 2018&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;I didn’t know how to handle routing in a generic way, so every time I added a
new page to the website I would have to manually add the path to a steadily
growing &lt;code&gt;index.js&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;js&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-js &quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;use strict&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;module.exports = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;function &lt;&#x2F;span&gt;&lt;span&gt;(app) {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;    app.get(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;newpage&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;function &lt;&#x2F;span&gt;&lt;span&gt;(req, res) {
&lt;&#x2F;span&gt;&lt;span&gt;        res.render(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;newpage&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    });
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;My &lt;code&gt;index.js&lt;&#x2F;code&gt; file was just several dozen lines of manually declared routes. I
could have implemented some kind of router, but this was beyond my knowledge and
curiosity at the time.&lt;&#x2F;p&gt;
&lt;p&gt;This strategy had a number of big disadvantages. Every time I updated my
website, I would have to complete a very manual routine:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;push my changes into GitHub&lt;&#x2F;li&gt;
&lt;li&gt;SSH into the server&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git pull&lt;&#x2F;code&gt; the latest changes&lt;&#x2F;li&gt;
&lt;li&gt;restart the Node.js daemon&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I was also paying Digital Ocean $5&#x2F;month for this droplet, which was completely
unnecessary when GitHub Pages and similar services will host your quiet static
blog on a wonderful CDN for free.&lt;&#x2F;p&gt;
&lt;p&gt;This was a very manual process — I was using Node to the full extent of my
unsophistication. But I knew this website could be built much better, and what
more noble purpose can a side project fulfill than by teaching you something
meaningful?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;generation-2-0-gatsby&quot;&gt;Generation 2.0 – Gatsby&lt;a class=&quot;zola-anchor&quot; href=&quot;#generation-2-0-gatsby&quot; aria-label=&quot;Anchor link for: generation-2-0-gatsby&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The first ‘generation’ of my website was focused on projects I worked on during
high school. Now I was more keen about writing, and by 2019, I had enough of my
tedious workflow that was wholly inadequate for blogging. I learned about static
site generators and how Gatsby was super powerful and extensible.&lt;&#x2F;p&gt;






























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;gatsby.fdac0945faa165a0.jpg&quot;
        class=&quot;&quot; alt=&quot;Featured sites made with Gatsby&quot;  width=977 &#x2F;&gt;
    &lt;figcaption&gt;Seeing all these beautiful websites made with
Gatsby, I had a sense of tech stack FOMO drift into my decision-making.&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;I found a well-received &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;alxshelepenok&#x2F;gatsby-starter-lumen&quot;&gt;Gatsby
starter&lt;&#x2F;a&gt; for the new
incarnation of my website, and got to work adjusting the theme to my taste.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s see what this theme consists of, without any modification yet.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;├── CHANGELOG.md
&lt;&#x2F;span&gt;&lt;span&gt;├── CODE_OF_CONDUCT.md
&lt;&#x2F;span&gt;&lt;span&gt;├── CONTRIBUTING.md
&lt;&#x2F;span&gt;&lt;span&gt;├── Dockerfile.development
&lt;&#x2F;span&gt;&lt;span&gt;├── Dockerfile.production
&lt;&#x2F;span&gt;&lt;span&gt;├── LICENSE
&lt;&#x2F;span&gt;&lt;span&gt;├── README.md
&lt;&#x2F;span&gt;&lt;span&gt;├── config.js
&lt;&#x2F;span&gt;&lt;span&gt;├── content
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── pages
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── about.md
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── contacts.md
&lt;&#x2F;span&gt;&lt;span&gt;│   └── posts
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── 2016-01-09---Perfecting-the-Art-of-Perfection.md
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── 2016-01-12---The-Origins-of-Social-Stationery-Lettering.md
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── 2016-02-02---A-Brief-History-of-Typography.md
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── 2017-18-08---The-Birth-of-Movable-Type.md
&lt;&#x2F;span&gt;&lt;span&gt;│       └── 2017-19-08---Humane-Typography-in-the-Digital-Age.md
&lt;&#x2F;span&gt;&lt;span&gt;├── docker-compose.development.yml
&lt;&#x2F;span&gt;&lt;span&gt;├── docker-compose.production.yml
&lt;&#x2F;span&gt;&lt;span&gt;├── flow
&lt;&#x2F;span&gt;&lt;span&gt;│   └── css-module-stub.js
&lt;&#x2F;span&gt;&lt;span&gt;├── flow-typed
&lt;&#x2F;span&gt;&lt;span&gt;│   └── npm
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── classnames_v2.x.x.js
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── gatsby_vx.x.x.js
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── jest_v24.x.x.js
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── lodash_v4.x.x.js
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── netlify-cms-app_vx.x.x.js
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── react-disqus-comments_vx.x.x.js
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── react-helmet_vx.x.x.js
&lt;&#x2F;span&gt;&lt;span&gt;│       └── react-test-renderer_v16.x.x.js
&lt;&#x2F;span&gt;&lt;span&gt;├── gatsby
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── create-pages.js
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── on-create-node.js
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── on-render-body.js
&lt;&#x2F;span&gt;&lt;span&gt;│   └── pagination
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── create-categories-pages.js
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── create-posts-pages.js
&lt;&#x2F;span&gt;&lt;span&gt;│       └── create-tags-pages.js
&lt;&#x2F;span&gt;&lt;span&gt;├── gatsby-browser.js
&lt;&#x2F;span&gt;&lt;span&gt;├── gatsby-config.js
&lt;&#x2F;span&gt;&lt;span&gt;├── gatsby-node.js
&lt;&#x2F;span&gt;&lt;span&gt;├── gatsby-ssr.js
&lt;&#x2F;span&gt;&lt;span&gt;├── jest
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── __fixtures__
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── all-markdown-remark.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── markdown-remark.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── page-context.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── site-metadata.js
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── __mocks__
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── file-mock.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── gatsby.js
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── jest-config.js
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── jest-preprocess.js
&lt;&#x2F;span&gt;&lt;span&gt;│   └── loadershim.js
&lt;&#x2F;span&gt;&lt;span&gt;├── netlify.toml
&lt;&#x2F;span&gt;&lt;span&gt;├── package.json
&lt;&#x2F;span&gt;&lt;span&gt;├── postcss-config.js
&lt;&#x2F;span&gt;&lt;span&gt;├── renovate.json
&lt;&#x2F;span&gt;&lt;span&gt;├── scripts
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── update_changelog.sh
&lt;&#x2F;span&gt;&lt;span&gt;│   └── update_release_notes.sh
&lt;&#x2F;span&gt;&lt;span&gt;├── src
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── assets
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── _base.scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── _mixins.scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── _variables.scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── base
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── init.scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │       └── mixins
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── cms
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── index.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── preview-templates
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── page-preview.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │       └── post-preview.js
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── components
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── Feed
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Feed.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Feed.module.scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Feed.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── __snapshots__
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   └── index.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── Icon
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Icon.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Icon.module.scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Icon.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── __snapshots__
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   └── index.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── Layout
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Layout.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Layout.module.scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Layout.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── __snapshots__
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   └── index.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── Page
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Page.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Page.module.scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Page.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── __snapshots__
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   └── index.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── Pagination
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Pagination.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Pagination.module.scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Pagination.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── __snapshots__
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   └── index.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── Post
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Author
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Comments
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Content
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Meta
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Post.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Post.module.scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Post.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── Tags
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── __snapshots__
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   └── index.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── Sidebar
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── Author
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── Contacts
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── Copyright
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── Menu
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── Sidebar.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── Sidebar.module.scss
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── Sidebar.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │       ├── __snapshots__
&lt;&#x2F;span&gt;&lt;span&gt;│   │       └── index.js
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── constants
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── icons.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── index.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── pagination.js
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── hooks
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── index.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── use-categories-list.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── use-site-metadata.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── use-tags-list.js
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── templates
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── __snapshots__
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── categories-list-template.test.js.snap
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── category-template.test.js.snap
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── index-template.test.js.snap
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── not-found-template.test.js.snap
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── page-template.test.js.snap
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── post-template.test.js.snap
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── tag-template.test.js.snap
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   └── tags-list-template.test.js.snap
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── categories-list-template.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── categories-list-template.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── category-template.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── category-template.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── index-template.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── index-template.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── not-found-template.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── not-found-template.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── page-template.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── page-template.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── post-template.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── post-template.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── tag-template.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── tag-template.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── tags-list-template.js
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── tags-list-template.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── types
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── index.js
&lt;&#x2F;span&gt;&lt;span&gt;│   └── utils
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── get-contact-href.js
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── get-contact-href.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── get-icon.js
&lt;&#x2F;span&gt;&lt;span&gt;│       ├── get-icon.test.js
&lt;&#x2F;span&gt;&lt;span&gt;│       └── index.js
&lt;&#x2F;span&gt;&lt;span&gt;├── static
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── admin
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── config.yml
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── css
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── katex
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   ├── fonts
&lt;&#x2F;span&gt;&lt;span&gt;│   │   │   └── katex.min.css
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── prismjs
&lt;&#x2F;span&gt;&lt;span&gt;│   │       └── theme.min.css
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── media
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── 42-line-bible.jpg
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── cpu.svg
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── gutenberg.jpg
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── image-0.jpg
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── image-1.jpg
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── image-2.jpg
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── image-3.jpg
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── image-4.jpg
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── movable-type.jpg
&lt;&#x2F;span&gt;&lt;span&gt;│   │   ├── printing-press.jpg
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── type-through-time.jpg
&lt;&#x2F;span&gt;&lt;span&gt;│   └── photo.jpg
&lt;&#x2F;span&gt;&lt;span&gt;└── yarn.lock
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Wow 😅! What a fun time trying to initially grok the structure of this project.
One of my first concerns was why I had so many seemingly vestigial configuration
options. What do each of the &lt;code&gt;gatsby-*.js&lt;&#x2F;code&gt; files mean? Does a static blog
designed to be served with GitHub Pages really need server-side rendering?
Managing the complexity of this setup felt like operating a 747.&lt;&#x2F;p&gt;






























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;gen2.ab2f15d0253f1ea1.jpg&quot;
        class=&quot;&quot; alt=&quot;Second generation chengeric.com&quot;  width=977 &#x2F;&gt;
    &lt;figcaption&gt;The second version of this website sometime in
the fall of 2021&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The modularity of this codebase ended up becoming very unwieldly; I would really
have to go fishing to find the component that I wanted to edit the appearance
of. This significantly hindered my ability to form a mental map of how&#x2F;where&#x2F;why
things worked.&lt;&#x2F;p&gt;
&lt;p&gt;One day, I wanted to add a “X min reading time” label to my articles. After
installing &lt;code&gt;gatsby-remark-reading-time&lt;&#x2F;code&gt;, I had to edit my &lt;code&gt;gatsby-config.js&lt;&#x2F;code&gt; and
then create an appropriate GraphQL query to generate the reading time itself for
each post. This ended up requiring a lot of time fighting GraphQL to do what I
needed. GraphQL seems like a promising tool, but it only ended up adding
additional moving parts (and points of failure) to an already unsteady
foundation.&lt;&#x2F;p&gt;
&lt;p&gt;This next gripe is more of a npm woe. I thought that using dependabot to
automatically update my dependencies would alleviate some of my maintenance
workload, but this disfigured my &lt;code&gt;package.json&lt;&#x2F;code&gt; so badly that it was completely
impossible to restore a working environment.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, I had deviated so far from the original Gatsby starter that
simply trying to mimic the original dependency set wouldn’t work, because the
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;alxshelepenok&#x2F;gatsby-starter-lumen&#x2F;issues&#x2F;1029&quot;&gt;original repo is also broken and unmaintained
now&lt;&#x2F;a&gt;. A few
months passed between inadvertently scuttling this website and finally
rebuilding it in Zola. During that time, I couldn’t edit this website at all,
which was deeply frustrating whenever I had the inspiration to write a post or
add something interesting to my &lt;a href=&quot;&#x2F;reading&quot;&gt;reading list&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Even if I had a much stronger and intricate understanding of how my dependency
graph worked, it would have still probably taken me hours to unblock myself.
Hours that I could have spent being productive, or better enjoying my leisure
time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;generation-3-0-zola&quot;&gt;Generation 3.0 – Zola&lt;a class=&quot;zola-anchor&quot; href=&quot;#generation-3-0-zola&quot; aria-label=&quot;Anchor link for: generation-3-0-zola&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I now use &lt;a href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt;, which packages all the functionality
you would need (and like) for a static site — Sass compilation, syntax
highlighting for code blocks, image optimization, markdown support, table of
contents, and more — into a simple binary. These features would have each
demanded a battery of npm packages to achieve the same functionality, and risks
shattering whenever some maintainer gets bored and stops updating their npm
package.&lt;&#x2F;p&gt;
&lt;p&gt;The “X min reading time” that I spent an hour trying to implement in Gatsby?
With Zola, it’s automatically provided in &lt;a href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;documentation&#x2F;templates&#x2F;pages-sections&#x2F;&quot;&gt;post
metadata&lt;&#x2F;a&gt;, so
all I got to do is simply reference &lt;code&gt;reading_time&lt;&#x2F;code&gt; in my HTML template.&lt;&#x2F;p&gt;
&lt;p&gt;If I wanted to edit this website from a fresh setup, I need to run the following
commands:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ git clone git@github.com:eh8&#x2F;MY_WEBSITE
&lt;&#x2F;span&gt;&lt;span&gt;$ cd MY_WEBSITE
&lt;&#x2F;span&gt;&lt;span&gt;$ zola serve
&lt;&#x2F;span&gt;&lt;span&gt;Building site...
&lt;&#x2F;span&gt;&lt;span&gt;Checking all internal links with anchors.
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; Successfully checked 1 internal link(s) with anchors.
&lt;&#x2F;span&gt;&lt;span&gt;-&amp;gt; Creating 8 pages (0 orphan) and 1 sections
&lt;&#x2F;span&gt;&lt;span&gt;Done in 21ms.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Web server is available at http:&#x2F;&#x2F;127.0.0.1:1111
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I now have a browser tab open with live-reload enabled, ready to go. From start
to finish, this whole process took about &lt;strong&gt;15 seconds&lt;&#x2F;strong&gt;. Herein lies the two
greatest benefits of Zola over Gatsby for small blogs: it’s super fast and super
simple. Contrast this workflow to running &lt;code&gt;npm install&lt;&#x2F;code&gt;, waiting a few minutes
for the command to churn, and then hoping &lt;code&gt;npm start&lt;&#x2F;code&gt; works on the first shot.&lt;&#x2F;p&gt;








&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;npm.de40a00ab8496fca.png&quot; class= &#x2F;&gt;
&lt;p&gt;Granted, I didn’t need to run &lt;code&gt;npm install&lt;&#x2F;code&gt; every time I edited my site. But
even the time spent waiting for &lt;code&gt;npm start&lt;&#x2F;code&gt; is non negligible.&lt;&#x2F;p&gt;
&lt;p&gt;Zola is considerably faster than Jekyll and indiscernibly slower than Hugo for a
basic blog like this website. It doesn’t need much tweaking because its default
“batteries included” feature set is so strong. I also considered
&lt;a href=&quot;https:&#x2F;&#x2F;www.11ty.dev&#x2F;&quot;&gt;Eleventy&lt;&#x2F;a&gt;, but found it too complicated and yet somewhat
lacking in features that Zola provides natively.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I would rather spend my time building a non-Node website that requires a higher
fixed learning cost, than having to spend my time afterwards regularly fighting
dependency errors and deprecated settings on a Node website that was initially
easy to spin up. But as it turns out, Zola can be learned in an afternoon or
two, so I didn’t have to pay much of a fixed learning cost after all.&lt;&#x2F;p&gt;
&lt;p&gt;With Zola, I don’t need to worry about deleting &lt;code&gt;node_modules&#x2F;&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; as a
last-ditch way of getting my site to work, and then waiting for &lt;code&gt;npm install&lt;&#x2F;code&gt; to
rebuild my dependencies. I can confidently write from macOS and Arch Linux
interchangeably with the exact same procedures and tooling. I know that I can
neglect this website for months on end and return to a productive workflow
immediately.&lt;&#x2F;p&gt;
&lt;p&gt;Every push to this website’s repository triggers this GitHub action, which
rebuilds the site in about 35 seconds from the moment I push.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yml&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-yml &quot;&gt;&lt;code class=&quot;language-yml&quot; data-lang=&quot;yml&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;Build and deploy on push&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;shalzz&#x2F;zola-deploy-action&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;runs-on&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;ubuntu-latest&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;steps&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;uses&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;actions&#x2F;checkout@master&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;shalzz&#x2F;zola-deploy-action&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;uses&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;shalzz&#x2F;zola-deploy-action@master&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;env&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;PAGES_BRANCH&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;gh-pages&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;BUILD_DIR&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;.
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;BUILD_THEMES&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;GITHUB_TOKEN&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A comparable Node workflow running &lt;code&gt;npm install&lt;&#x2F;code&gt; and &lt;code&gt;gatsby build&lt;&#x2F;code&gt; would
probably last 10x longer. And with this saved time, I get to think more about
writing stuff.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;KISS_principle&quot;&gt;Keep it simple, stupid!&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;archlinux&#x2F;comments&#x2F;4lzxs3&#x2F;why_did_archlinux_embrace_systemd&#x2F;&quot;&gt;u&#x2F;2brainz talks about transitioning Arch Linux to
systemd&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;For instance, you can toggle HTML and CSS minification in Zola by enabling
&lt;code&gt;minify_html = true&lt;&#x2F;code&gt; in &lt;code&gt;config.toml&lt;&#x2F;code&gt;. Achieving the same effect in Eleventy
requires installing some npm plugins and configuring them with some code
you’re inevitably going to copy and paste from Google.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Which would often exceed 1 GB&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Backups: the good, the bad, and the ugly</title>
        <published>2022-03-31T00:00:00+00:00</published>
        <updated>2022-03-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/backups/"/>
        <id>https://www.chengeric.com/backups/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/backups/">&lt;p&gt;If you think something is valuable, then you should back it up.&lt;&#x2F;p&gt;
&lt;p&gt;For over a year now, I’ve been using &lt;a href=&quot;https:&#x2F;&#x2F;kopia.io&quot;&gt;Kopia&lt;&#x2F;a&gt; to back up my
Nextcloud installation and other important homelab files into S3.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Kopia is
an incredibly powerful and underappreciated tool that should be equipped more
often in the toolbelts of amateur sysadmins and open-source nerds. To me, Kopia
is to backups as WireGuard is to VPNs.&lt;&#x2F;p&gt;
&lt;p&gt;But things were a lot rougher before I smoothened my process out.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-bad-and-the-ugly&quot;&gt;The bad and the ugly&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-bad-and-the-ugly&quot; aria-label=&quot;Anchor link for: the-bad-and-the-ugly&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;None of the programs that I’m about to describe are necessarily poor choices,
they’re just incompatible with my specific use case and requirements. However,
I suspect that my &lt;a href=&quot;https:&#x2F;&#x2F;www.chengeric.com&#x2F;backups&#x2F;#retrospective&quot;&gt;goals&lt;&#x2F;a&gt; will resonate with other homelab
enthusiasts.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;duplicity&quot;&gt;Duplicity&lt;a class=&quot;zola-anchor&quot; href=&quot;#duplicity&quot; aria-label=&quot;Anchor link for: duplicity&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I first used &lt;a href=&quot;https:&#x2F;&#x2F;duplicity.gitlab.io&#x2F;&quot;&gt;Duplicity&lt;&#x2F;a&gt;, but it felt rather
dated. Indeed, the program has been around since August 2002, so one of my early
obstacles learning how to use Duplicity was navigating stale 20 year old
documentation.&lt;&#x2F;p&gt;
&lt;p&gt;The big catch is that you can’t run incremental backups indefinitely without
compromising the performance of restoring files, so every once in a while you
will need to run a full backup. You then have to delete your full backups to
prevent them from bloating space. This adds unneeded complexity to a script.
Multithreading is also not supported, which strangled my upload throughput to
roughly 2 Mbps.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;duplicati&quot;&gt;Duplicati&lt;a class=&quot;zola-anchor&quot; href=&quot;#duplicati&quot; aria-label=&quot;Anchor link for: duplicati&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Seeking something better, I then discovered
&lt;a href=&quot;https:&#x2F;&#x2F;www.duplicati.com&#x2F;&quot;&gt;Duplicati&lt;&#x2F;a&gt;, another backup utility that comes with
a web UI. Unfortunately, the UI was often unresponsive or loaded an empty
dashboard, which was alarming since I feared my data was lost.&lt;&#x2F;p&gt;
&lt;p&gt;Frequent crashes furthered my distrust of the program in case I ever needed to
rely upon it to restore data. There are some horror stories circulating around
various forums about Duplicati corrupting data or just displaying poor restore
performance, so over time I got frustrated with my unreliable experience with
Duplicati and decided to move on.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;duplicacy&quot;&gt;Duplicacy&lt;a class=&quot;zola-anchor&quot; href=&quot;#duplicacy&quot; aria-label=&quot;Anchor link for: duplicacy&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I briefly used &lt;a href=&quot;https:&#x2F;&#x2F;duplicacy.com&#x2F;&quot;&gt;Duplicacy&lt;&#x2F;a&gt; but I wasn’t comfortable
paying licensing fees to solve a problem that ought to have a free and
open-source solution. This said, it was straight forward to use and I enjoyed
being able to backup data to Google Drive.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;timeshift&quot;&gt;Timeshift&lt;a class=&quot;zola-anchor&quot; href=&quot;#timeshift&quot; aria-label=&quot;Anchor link for: timeshift&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I used &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;teejee2008&#x2F;timeshift&quot;&gt;Timeshift&lt;&#x2F;a&gt; once to backup a
server but was unable to actually restore the data afterwards.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; This was very
sad.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;retrospective&quot;&gt;Retrospective&lt;a class=&quot;zola-anchor&quot; href=&quot;#retrospective&quot; aria-label=&quot;Anchor link for: retrospective&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;For reasons unknown to me, most backup programs for Linux fall short in one
crucial way. I had a list of wishes that grew with every deficiency I came
across:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;no nasty surprises when I had to restore something&lt;&#x2F;li&gt;
&lt;li&gt;no weird user intervention required to maintain backup health&lt;&#x2F;li&gt;
&lt;li&gt;support for backing up to a major cloud provider&lt;&#x2F;li&gt;
&lt;li&gt;solid CLI support for scripting&lt;&#x2F;li&gt;
&lt;li&gt;encryption&lt;&#x2F;li&gt;
&lt;li&gt;compression&lt;&#x2F;li&gt;
&lt;li&gt;dedeuplication&lt;&#x2F;li&gt;
&lt;li&gt;support for ARM architecture&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Of course, I wanted something that was designed to tackle all of these things
with ease. There are a ton of
&lt;a href=&quot;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;index.php&#x2F;Synchronization_and_backup_programs&quot;&gt;programs&lt;&#x2F;a&gt;
that you can work with, but I suspect that the illusion of choice is in full
swing here and there are only a few truly practical solutions for a long term
setup. For this reason, I considered using
&lt;a href=&quot;https:&#x2F;&#x2F;borgbackup.readthedocs.io&#x2F;en&#x2F;stable&#x2F;&quot;&gt;Borg&lt;&#x2F;a&gt; or
&lt;a href=&quot;https:&#x2F;&#x2F;restic.net&#x2F;&quot;&gt;restic&lt;&#x2F;a&gt;, two very popular backup programs for Linux users,
but deciding against the two once I found myself having to plan workarounds to
fit my above needs.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-good&quot;&gt;The good&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-good&quot; aria-label=&quot;Anchor link for: the-good&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;kopia.io&quot;&gt;Kopia&lt;&#x2F;a&gt; describes itself as&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Encrypted, deduplicated, and compressed data backups using your own cloud
storage&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;That tagline already fulfills a lot of my goals — off to a good start already.&lt;&#x2F;p&gt;
&lt;p&gt;It gets better:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;upload stuff to a variety of cloud backends such as AWS, Google Cloud
Platform, Azure, and Backblaze, in addition to local servers and filesystems.
As of April 2022, there is experimental support for Google Drive and
&lt;a href=&quot;https:&#x2F;&#x2F;rclone.org&#x2F;&quot;&gt;rclone&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;broad selection of encryption and compression algorithms&lt;&#x2F;li&gt;
&lt;li&gt;deploy Kopia to accomodate &lt;a href=&quot;https:&#x2F;&#x2F;docs.google.com&#x2F;presentation&#x2F;d&#x2F;1RUD6Xy53XweDmfHna7iIDoXRZ-KMktcMlDPHazIXl40&#x2F;edit?usp=sharing&quot;&gt;various organizational
scenarios&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;automatic repository health checks and cleanup&lt;&#x2F;li&gt;
&lt;li&gt;default retention settings are sane&lt;&#x2F;li&gt;
&lt;li&gt;written in Go, and therefore easily distributed as a binary&lt;&#x2F;li&gt;
&lt;li&gt;available for Linux, MacOS, Windows, *BSD&lt;&#x2F;li&gt;
&lt;li&gt;compatible with x64, armhf, and arm64&lt;&#x2F;li&gt;
&lt;li&gt;CLI, web,&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; and graphical interface offered&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;From anecdotal experience, Kopia is the fastest backup program I have ever used
on my ARM servers.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#6&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Niraj Tolia and Julio Lopez &lt;a href=&quot;https:&#x2F;&#x2F;blog.kasten.io&#x2F;benchmarking-kopia-architecture-scale-and-performance&quot;&gt;benchmarked
Kopia&lt;&#x2F;a&gt;
along with restic, and found that Kopia was up to 700% faster and 20% more space
efficient, and continues to show increasingly superior performance as Kopia
matures.&lt;&#x2F;p&gt;
&lt;p&gt;On top of all the good things I have already listed about Kopia, one understated
strength is how ergonomic it is when used from the command line. For instance,
it uses a policy system similar to &lt;code&gt;.gitignore&lt;&#x2F;code&gt; to exclude certain files or file
extensions, which removes a lot of the tedium when, say, writing a Bash script
to automate backups. Keep your data safe, and happy homelabing.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Backblaze B2 is cheaper, but university credits turn S3 into an offer you
can’t refuse. I’ll figure something out when my university credits are
depleted or expired.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Which has practically no storage limits if your university pays for Google
Drive.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Timeshift is often recommended to new users seeking a basic backup
solution with a decent GTK user instance. Unfortunately, the maintainer
seems to have abandoned active development on the project. The project
GitHub page is consequently filled with various unanswered bug reports and
pull requests.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;At the time of writing, Borg doesn’t have native support for cloud
backends and restic doesn’t offer compression.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;5&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;The web interface is a super convenient way to retrieve a versioned copy
of a particular file, almost like an open source version of Time Machine on
macOS.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;6&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.hardkernel.com&#x2F;shop&#x2F;odroid-hc1-home-cloud-one&#x2F;&quot;&gt;ODROID-HC1&lt;&#x2F;a&gt;,
which are not super powerful&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Fence</title>
        <published>2022-02-26T00:00:00+00:00</published>
        <updated>2022-02-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/fence/"/>
        <id>https://www.chengeric.com/fence/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/fence/">





























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;1.1624368b2533b7f5.jpg&quot;
        class=&quot;&quot; alt=&quot;ukraine fence reverse&quot;  width=1167 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;





























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;2.722929de101c9af6.jpg&quot;
        class=&quot;&quot; alt=&quot;ukraine fence front&quot;  width=1167 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;





























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;3.592f266859d53919.jpg&quot;
        class=&quot;&quot; alt=&quot;ukraine fence with hunt library&quot;  width=1167 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Do corrupt emerging markets respond to COVID-19 differently?</title>
        <published>2021-12-01T00:00:00+00:00</published>
        <updated>2021-12-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/emerging/"/>
        <id>https://www.chengeric.com/emerging/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/emerging/">&lt;p&gt;&lt;strong&gt;TL;DR:&lt;&#x2F;strong&gt; &lt;em&gt;Yes&lt;&#x2F;em&gt; — corrupt emerging markets respond to COVID-19 more
intensely.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;This past semester, I took an economics course about emerging markets.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#course&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
Our final project was researching and presenting any topic of our choosing so
long as it related to emerging markets. My team decided to investigate the
relationship between corruption and COVID-19 in emerging markets.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Whenever you read “emerging markets,” we are referring to economies that the
&lt;a href=&quot;https:&#x2F;&#x2F;www.imf.org&#x2F;external&#x2F;pubs&#x2F;ft&#x2F;fandd&#x2F;2021&#x2F;06&#x2F;the-future-of-emerging-markets-duttagupta-and-pazarbasioglu.htm&quot;&gt;IMF considers to be emerging
markets&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Longer TL;DR:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Corrupt emerging markets generally tend to be more autocratic, and autocratic
countries consequently clamped down on COVID-19 more severely.&lt;&#x2F;li&gt;
&lt;li&gt;This more extreme initial response was comparatively less effective.&lt;&#x2F;li&gt;
&lt;li&gt;In fact, corruption is correlated with a faster infection rate.&lt;&#x2F;li&gt;
&lt;li&gt;A potentially useful future model that reconciles corruption and autocracy
could be \(R = \beta te^{-\lambda t}\), where \(R\) is the severity of COVID-19
response, \(\beta\) is level of autocracy, \(\lambda\) is level of corruption,
and \(t\) is days since first case.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Let me see the
&lt;a href=&quot;https:&#x2F;&#x2F;www.dropbox.com&#x2F;s&#x2F;8brmnxbr1es7io7&#x2F;Do%20corrupt%20emerging%20markets%20respond%20to%20COVID-19%20differently.pdf?dl=0&quot;&gt;slides.&lt;&#x2F;a&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#disclaimer&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;course&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;If you wonder why the world looks the way it does economically, you
should consider taking 73-421.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;disclaimer&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;This is the work of amateur economists, so &lt;a href=&quot;mailto:economics@chengeric.com&quot;&gt;feel free to get in
touch&lt;&#x2F;a&gt; if you find something amiss, would
like to discuss further, or want to see our data.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The next era of Formula 1</title>
        <published>2021-02-09T00:00:00+00:00</published>
        <updated>2021-02-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/formula1/"/>
        <id>https://www.chengeric.com/formula1/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/formula1/">





























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;oldf1.b9045d4cf2625a84.jpg&quot;
        class=&quot;&quot; alt=&quot;During the 1968 European Grand Prix at
the Nürburgring&quot;  width=977 &#x2F;&gt;
    &lt;figcaption&gt;During the 1968 European
Grand Prix at the Nürburgring&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;I started following Formula 1 in high school and am happy to see it gaining
popularity in the United States. Despite its growing audience, I see two kinds
of problems within Formula 1: the urgent technical and financial concerns that
affect the sport now, and the grand themes of the sport that define its
long-term destiny.&lt;&#x2F;p&gt;
&lt;p&gt;In 2022, Formula 1 will fully unveil a brand new set of technical and
organizational regulations that will shape the next era of the sport. Right now,
concerns surrounding the sport’s immediate fate include the financial
sustainability of the teams, the burdens of the pandemic, eight years of
Mercedes dominance,&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; and various technical factors that make overtaking less
frequent than in previous eras of the sport. When the sport celebrates its
centennial Grand Prix in 2050, Formula 1 might be only be superficially
recognizable compared to today.&lt;&#x2F;p&gt;
&lt;p&gt;But there are larger issues at stake that Formula 1 can really only abstractly
claw at right now. These issues extend deeper into the identity of an
international sport navigating a world that is increasingly vigiliant of its
environment footprint, its inequality, and its human rights. F1 will, at some
point, confront these issues as they become necessary for the longevity of the
sport’s technological evolution, or its financial success.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;confronting-electrification&quot;&gt;Confronting electrification&lt;a class=&quot;zola-anchor&quot; href=&quot;#confronting-electrification&quot; aria-label=&quot;Anchor link for: confronting-electrification&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The gradual electrification of ordinary road cars led F1 to mandate a new
component of the powertrain: an electric battery that provides near-instant
acceleration throughout the race and harvests energy during braking. Since 2014,
this electrical system—dubbed KERS—has improved dramatically as teams discovered
more mature ways of integrating electrical energy in their cars. Such technology
improved the efficiency of the car and reduced its overall fuel consumption.&lt;&#x2F;p&gt;
&lt;p&gt;However, the main culprit behind F1’s massive carbon footprint are not the
actual race cars, but the logistics vehicles used to transport teams and
equipment across the different race venues across the world. Formula 1 estimated
that only 0.7% of its 2018 carbon emissions came from the race cars themselves,
with the main contributor being the trucks, airplanes, and cargo ships that
circulate throughout four continents during the race season. It really does
appear to be a difficult traveling saleman problem.&lt;&#x2F;p&gt;
&lt;p&gt;Formula 1 has committed itself to being carbon-neutral by 2030. Should F1
transition fully to electric race cars, usurping the existing all-electric
Formula-E racing series and embracing the next generation of automobile
technology? The logistical vehicles used to transport Formula 1 around the world
would also need to become greener, but a transition beginning from the race cars
would signal a clear message. This is a highly controversial stance, since the
combustion engine is intimately associated with Formula 1’s 70-year racing
history.&lt;&#x2F;p&gt;
&lt;p&gt;However, any changes to the race cars are only addressing a small portion of the
emissions produced by the sport, so an audience must bear in mind that the
needed reduction of greenhouse gases from Formula 1 will be largely out of view.&lt;&#x2F;p&gt;
&lt;p&gt;The race cars themselves are important when we consider that the automobile
industry is gradually shifting towards electric vehicles. Formula 1 has
traditionally been an experimental testing ground for innovation to trickle out
into consumer-grade road car technologies. This will no longer be the case if
engine manufacturers find themselves developing state of the art internal
combustion engines that are becoming increasingly irrelevant to their core
business model.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;driver-diversity&quot;&gt;Driver diversity&lt;a class=&quot;zola-anchor&quot; href=&quot;#driver-diversity&quot; aria-label=&quot;Anchor link for: driver-diversity&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The current drivers’ champion Lewis Hamilton is notable for being one of the
most decorated drivers in Formula 1 history, as well as being the only black
driver to ever compete.&lt;&#x2F;p&gt;
&lt;p&gt;F1 remains a sport that perennially features young European or American men from
wealthy backgrounds. A number of celebrated drivers have hailed from Asia and
South America, but over 91% of all drivers to have ever competed have hailed
from either the United States or Europe. This trend has not changed in the
21&lt;sup&gt;st&lt;&#x2F;sup&gt; century.&lt;&#x2F;p&gt;
&lt;p&gt;The factors contributing to this dynamic are well understood yet weakly
disrupted. There is a recursive diversity issue at every level of racing leading
to Formula 1, which is exacerbated by the increasingly expensive cost of raising
a racer. Formula 1 drivers earn their seats after graduating from successful
junior careers in feeder series such as Formula 2.&lt;&#x2F;p&gt;
&lt;p&gt;Junior drivers earn their seats after being selected from smaller, regional
karting competitions. We must see that at the earliest stages of a young
driver’s career, households must prepare to spend six-figure sums annually to
fund their children’s karting aspirations, which largely competes in western
Europe. As such, most drivers in F1 have been training to become racing drivers
for the majority of their lives. The reality of racing shows that young boys are
placed in these formative karting careers more often than young girls, and the
exclusivity of the sport to the wealthiest households limits the total sample
size of young drivers. An all-female racing championship called W Series was
introduced in 2019 to encourage female participation in motorsport, but this has
received various criticisms centered around the implication that females are
segregated from entering Formula 1.&lt;&#x2F;p&gt;
&lt;p&gt;Most people have the basic impression that the sport will &lt;em&gt;eventually&lt;&#x2F;em&gt; debut
more diverse drivers. Furthermore, most developed economies have staged various
educational efforts for women and historically disadvantages minorities to
pursue STEM educations and careers. However, research in the US has shown that
women pursue STEM careers less frequently than men despite earning higher grades
in such subjects. There are pervasive cultural norms that hinder gender parity
in STEM, and I wouldn’t be surprised that in the current state of things, the
sport’s driver composition won’t fundamentally change much.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;human-rights&quot;&gt;Human rights&lt;a class=&quot;zola-anchor&quot; href=&quot;#human-rights&quot; aria-label=&quot;Anchor link for: human-rights&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;While Formula 1’s commitment to inclusivity, diversity, and other popular human
rights rhetoric has been generally well received, the sport is criticized for
turning a blind eye towards human rights controversies that implicate sponsors
and race venues.&lt;&#x2F;p&gt;
&lt;p&gt;Sportswashing is the practice of hosting high-profile athletic events in
countries with a poor reputation of protecting human rights. Such accusations
have long been levied on Formula 1; in years past F1 has been criticized for
racing in Bahrain, Russia, and China.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Recently, the announcement that
Formula 1 would host the inaugural Saudi Arabian Grand Prix in 2021 drew
criticism from Amnesty International and Human Rights Watch.&lt;&#x2F;p&gt;
&lt;p&gt;Since Formula 1’s financial and venue decision making are closely linked,
navigating the implications of selecting a country to host a race is a
controversial activity. Any international sport will encounter the same
obstacles. Formula 1 must do so while avoiding the slippery slope of rejecting
all race venues based on historical misdeeds.&lt;&#x2F;p&gt;
&lt;p&gt;In rare instances Formula 1 has shown clear resolve in the face of a social
crisis, but generally only if there is overwhelming worldwide outcry. The 1985
South African Grand Prix was notable for being boycotted by some teams due to
apartheid. The French government prohibited French teams Ligier and Renault from
competing and a number of sponsors withdrew their branding from cars in
preparation for the race. Shortly after the race, Formula 1 withdrew plans for
planned races in South Africa due to the ongoing global apartheid protests.&lt;&#x2F;p&gt;
&lt;p&gt;The troubling nature of Formula 1’s current positioning is that it must somehow
unite its values with the very different cultural standards of its benefactors.
This is no simple task, and has beset even the Olympics on a number of
occasions. But if Formula 1 is to continue with its stance of promoting social
justice and equality, then it ought to actively enforce its values beyond a
marketing campaign.&lt;&#x2F;p&gt;






























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;f1.2cf5b575459c1046.jpg&quot;
        class=&quot;&quot; alt=&quot;Mercedes F1 car in 2020&quot;  width=977 &#x2F;&gt;
    &lt;figcaption&gt;Mercedes executing a practice pitstop in 2020&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;When the V6 turbo-hybrid engine debuted in 2014, Mercedes responded with
the best overall car. It turns out that in Formula 1, this kind of early
success usually leads to a positive feedback loop.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;To which some then pointed out that F1 races in the United States and the
United Kingdom as a kind of exercise in whataboutery.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Checking dining hall hours → cmueats.com</title>
        <published>2018-10-01T00:00:00+00:00</published>
        <updated>2018-10-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/cmueats/"/>
        <id>https://www.chengeric.com/cmueats/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/cmueats/">&lt;p&gt;As a freshman, I always check dining hall hours online. But CMU’s dining hall
page is clunky and ill-optimized for mobile devices. To remedy this, CMU
students created their own third-party website to tracking dining hour hours:
&lt;a href=&quot;https:&#x2F;&#x2F;cmueats.com&quot;&gt;cmueats.com&lt;&#x2F;a&gt;. Though faster to load and easier to read,
cmueats.com was still hamstrung by its dated design.&lt;&#x2F;p&gt;
&lt;p&gt;So I went and redesigned cmueats.com, whose design had not undergone any changes
for over two years. To begin with, I wanted to increase the density of the
website’s information, so that users may more quickly identify eateries and
their hours. But most of all, I wanted a redesign that would encourage more
regular users and improve the dining experience at Carnegie Mellon.&lt;&#x2F;p&gt;
&lt;p&gt;I worked with React for the first time for CMUEats, and tinkering with the
existing code was a pleasant learning experience.&lt;&#x2F;p&gt;
&lt;p&gt;CMUEats began as a HackCMU submission in September 2013, originally created by
Oscar Bezi, Kirn Hans and Justin Gallagher. I worked with Emily Newman, the
then-current steward of the cmueats.com project, to deploy the new changes.&lt;&#x2F;p&gt;




























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;cmueats-2013.5f6999ca0783a9e8.jpg&quot;
        class=&quot;&quot; alt=&quot;The original version of cmueats.com
back in October 2013&quot;  width=977 &#x2F;&gt;
    &lt;figcaption&gt;The original version of
cmueats.com back in October 2013&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;



























&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;cmueats-2020.db6fc2a804903cb3.jpg&quot;
        class=&quot;&quot; alt=&quot;The current version of cmueats.com
as of 2020&quot;  width=977 &#x2F;&gt;
    &lt;figcaption&gt;The current version of cmueats.com
as of 2020&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Want to see what CMUEats looks like today? &lt;a href=&quot;https:&#x2F;&#x2F;cmueats.com&quot;&gt;Give it a
look!&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Classifying colleges with machine learning</title>
        <published>2018-07-18T00:00:00+00:00</published>
        <updated>2018-07-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.chengeric.com/colleges/"/>
        <id>https://www.chengeric.com/colleges/</id>
        
        <content type="html" xml:base="https://www.chengeric.com/colleges/">&lt;p&gt;Americans are attending college in ever increasing numbers. An estimated 20
million students are expected to attend college or university immediately
following high school graduation, as of fall 2017, which represents an increase
of 5 million since 2000.&lt;&#x2F;p&gt;
&lt;p&gt;This project seeks to classify whether a college is private or public based on
predictor variables including out of state tuition, acceptance rate, percentage
of incoming freshman class that were in the top 10% of their high school class,
etc. There are therefore two classes—and two levels—of the response variable.
The factors listed below may considered by a college applicant in his or her
college search.&lt;&#x2F;p&gt;
&lt;p&gt;Because the choice of attending either a public or private university is
influenced by several factors, this project may provide assistance to those
seeking to decide by assessing how much a certain university conforms to the
typical, expected characteristics of a private or public university.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pre-processing&quot;&gt;Pre-processing&lt;a class=&quot;zola-anchor&quot; href=&quot;#pre-processing&quot; aria-label=&quot;Anchor link for: pre-processing&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;For all the classification methods, a training set was created using 80% of the
original data set while a portion of the data set was reserved as a test set to
see how the data would respond to new information, as shown. The original, full
data set consisted of 777 colleges, so a split of 80% would yield a training set
and test set of 622 and 155 colleges, respectively. These quantities would both
yield acceptable sample sizes, with a larger training set for the purpose of
creating more refined models.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;decision-trees&quot;&gt;Decision trees&lt;a class=&quot;zola-anchor&quot; href=&quot;#decision-trees&quot; aria-label=&quot;Anchor link for: decision-trees&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Decision trees separate data by explanatory variables to generate subsets of the
data that are distinct to one another, but internally similar. In other words,
decision trees generate homogeneous groups with maximized heterogeneity between
them.&lt;&#x2F;p&gt;
&lt;p&gt;One term used frequently in the discussion of trees is ‘pruning,’ or the removal
of sub-nodes from their respective decision nodes. Low pruning can result in
overfitting, while high pruning will lead to large variance, as reflected by
less homogeneous groups at each node.&lt;&#x2F;p&gt;
&lt;p&gt;We decided to use decisions trees first in the production of this report, so
that we may find the most influential variables for future classification
models, a feature of ‘random bagging.’&lt;&#x2F;p&gt;
&lt;p&gt;A general tree model is provided below.&lt;&#x2F;p&gt;
































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;Rplot04.5b5d066e112bda59.png&quot;
        class=&quot;&quot; alt=&quot;college diagram&quot;  width=977 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;Another tree was generated using this lower (less pruning) setting, shown below.&lt;&#x2F;p&gt;
































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;Rplot05.c19a9c3851fdb612.png&quot;
        class=&quot;&quot; alt=&quot;college diagram&quot;  width=977 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;An important component of trees is random forest, which helps determine which
variables have the most impact on the data.&lt;&#x2F;p&gt;
































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;Rplot06.ab064218efb62973.png&quot;
        class=&quot;&quot; alt=&quot;college diagram&quot;  width=977 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;&lt;h2 id=&quot;linear-discriminant-analysis&quot;&gt;Linear discriminant analysis&lt;a class=&quot;zola-anchor&quot; href=&quot;#linear-discriminant-analysis&quot; aria-label=&quot;Anchor link for: linear-discriminant-analysis&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Linear discriminant analysis maximizes separability between a ‘k’ number of
classes via dimension reduction. In our case, this means two classes: private
and public colleges.&lt;&#x2F;p&gt;
&lt;p&gt;Linear discriminant analysis will maximize the distance between the means of
each class while minimizing the variation within each class. So long as a
minimum of two classes are involved, this process works.&lt;&#x2F;p&gt;
































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;Rplot03.e74f47c13810654d.png&quot;
        class=&quot;&quot; alt=&quot;college diagram&quot;  width=977 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;Our training error was 0.093, which is fairly accurate. Consider that random
guessing would yield a training error of 0.50.&lt;&#x2F;p&gt;
































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;Rplot09.ba07185a5df9e6c5.png&quot;
        class=&quot;&quot; alt=&quot;college diagram&quot;  width=977 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;&lt;h2 id=&quot;k-nearest-neighbor&quot;&gt;K-nearest neighbor&lt;a class=&quot;zola-anchor&quot; href=&quot;#k-nearest-neighbor&quot; aria-label=&quot;Anchor link for: k-nearest-neighbor&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;K-nearest neighbor classifies the sample’s response variable based on what the
closest point is classified as. So, essentially, the training set is used to
create a model of space closest to a certain point. The test set is then applied
to the model. The training set point that is closest to the test set point will
be classified the same. The test error is .096.&lt;&#x2F;p&gt;
































&lt;figure class=&quot;extended-figure&quot; &gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.chengeric.com&amp;#x2F;processed_images&amp;#x2F;Rplot08.9e0373b040530e70.png&quot;
        class=&quot;&quot; alt=&quot;college diagram&quot;  width=977 &#x2F;&gt;
    
&lt;&#x2F;figure&gt;&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusions&quot; aria-label=&quot;Anchor link for: conclusions&quot;&gt;&lt;sup&gt;↗&lt;&#x2F;sup&gt;&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The decision tree was first used to determine the best predictor for our
response variable. The tree showed that the out of state tuition (Outstate) was
the best predictor for whether or not the college or university was private.
This is consistent with the implications of the other classification methods
specifically kNN. The kNN graphs with the lowest error all had out-of-state
tuition as a explanatory variable, providing further evidence that ‘outstate’ is
the best predictor for the response variable.&lt;&#x2F;p&gt;
&lt;p&gt;The best classification method was LDA using out of state tuition and enrollment
as explanatory variables, with a training error of 0.093 (test error oddly of
0). This result was followed closely by kNN, which produced a respectable test
error of 0.096. Decision trees were able to produce a model that had a
cross-validated error of 0.198.&lt;&#x2F;p&gt;
&lt;p&gt;The effectiveness of these particular models is somewhat remarkable in
retrospect, for both a model that depends upon a linearized trend line and a
model that uses proximity-based determination produced very similar accuracy
figures. However, the data was fairly separated to begin with, so this made for
a particularly easier classification task.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
