<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:base="https://philcrockett.com/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Phil&#39;s Notes</title>
    <link>https://philcrockett.com/</link>
    <atom:link href="https://philcrockett.com/feed.xml" rel="self" type="application/rss+xml" />
    <description>Notes from my definitely-not-a-blog</description>
    <language>en</language>
    <item>
      <title>Systemd Targets and Dependencies</title>
      <link>https://philcrockett.com/notes/2026/01/25/systemd-targets-and-dependencies/</link>
      <description>&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; If you know the background details and just need some quick syntax reminders,
checkout the &lt;a href=&quot;https://philcrockett.com/notes/2026/01/25/systemd-targets-and-dependencies/#summary&quot;&gt;summary at the bottom&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I modify systemd unit files maybe a couple of times per year. That’s often enough that
it’s useful for me to understand them well, but not often enough for those details to
stick in my brain.&lt;/p&gt;
&lt;p&gt;So I wrote this for myself or for anyone else who might be in a similar situation.
It’s for anyone who needs a quick refresher on systemd targets, &lt;code&gt;Wants=&lt;/code&gt;, &lt;code&gt;Requires=&lt;/code&gt;,
&lt;code&gt;WantedBy=&lt;/code&gt;, &lt;code&gt;RequiredBy=&lt;/code&gt;, &lt;code&gt;Before=&lt;/code&gt;, and &lt;code&gt;After=&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before I get into the real content, it’s useful to have an example systemd unit file
in your head for context. I chose Tailscale (copy / pasted from my laptop running
Archlinux):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;# /usr/lib/systemd/system/tailscaled.service
[Unit]
# Details omitted for brevity
Wants=network-pre.target
After=network-pre.target NetworkManager.service systemd-resolved.service

[Service]
# Details omitted for brevity

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-dependency-graph&quot; tabindex=&quot;-1&quot;&gt;The Dependency Graph&lt;/h2&gt;
&lt;p&gt;Systemd maintains a dependency graph of units.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2026/01/25/systemd-targets-and-dependencies/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; These units can include,
for example, generic “targets” (which describe overall system states) such as
&lt;code&gt;network-online.target&lt;/code&gt;, or specific background services like &lt;code&gt;tailscaled.service&lt;/code&gt;.
There are other kinds of systemd units, but these are the most common types we interact
with.&lt;/p&gt;
&lt;p&gt;This dependency graph is important because as your system changes state (online vs.
offline, starting up vs. shutting down, etc.), certain things must happen in a specific
order. For instance, it doesn’t make sense to start the Tailscale service before your
DNS resolver is ready.&lt;/p&gt;
&lt;p&gt;A key strength of systemd’s design is that you can precisely add entries to this graph
without performing invasive surgery on your operating system.&lt;/p&gt;
&lt;p&gt;Most of what follows applies regardless of whether you’re working with targets,
services, or other types of systemd &lt;strong&gt;units&lt;/strong&gt; — the concepts are largely consistent
across unit types.&lt;/p&gt;
&lt;h2 id=&quot;activation-states&quot; tabindex=&quot;-1&quot;&gt;Activation States&lt;/h2&gt;
&lt;p&gt;When a unit is activated, it eventually reaches a final activation state: either
“active” or “failed.” If a unit was never intended to be activated, it remains
“inactive.”&lt;/p&gt;
&lt;p&gt;Understanding these states is important for understanding the difference between
“wanting” and “requiring” another unit.&lt;/p&gt;
&lt;h2 id=&quot;establishing-a-basic-dependency-relationship&quot; tabindex=&quot;-1&quot;&gt;Establishing a Basic Dependency Relationship&lt;/h2&gt;
&lt;p&gt;When writing a unit file, the most basic way to establish a dependency on another unit
is using &lt;code&gt;Wants=&lt;/code&gt; and &lt;code&gt;Requires=&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Wants=&lt;/code&gt; creates a soft dependency. If your unit includes &lt;code&gt;Wants=&lt;/code&gt;, systemd will
attempt to start the specified unit alongside yours. If that unit fails to activate,
it doesn’t matter — your unit will still start.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Requires=&lt;/code&gt; creates a hard dependency. It behaves similarly to &lt;code&gt;Wants=&lt;/code&gt;, but if the
target unit ends up in a “failed” state, your unit &lt;strong&gt;will not&lt;/strong&gt; start. Or, if both
were being started in parallel, your unit will be stopped.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In both cases, &lt;code&gt;Wants=&lt;/code&gt; and &lt;code&gt;Requires=&lt;/code&gt; cause systemd to include the dependent unit in
the same transaction. The difference lies in how failure is handled.&lt;/p&gt;
&lt;h2 id=&quot;reverse-dependencies&quot; tabindex=&quot;-1&quot;&gt;Reverse Dependencies&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;WantedBy=&lt;/code&gt; and &lt;code&gt;RequiredBy=&lt;/code&gt; directives let you define a dependency &lt;strong&gt;from another
unit back to yours&lt;/strong&gt; — effectively reversing the dependency direction.&lt;/p&gt;
&lt;p&gt;These directives cause symbolic links to be created. For example, if your unit
specifies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;systemd creates a symlink:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/etc/systemd/system/multi-user.target.wants/my-service.service → /usr/lib/systemd/system/my-service.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures your unit starts during the activation of &lt;code&gt;multi-user.target&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what%E2%80%99s-up-with-the-%5Binstall%5D-section%3F&quot; tabindex=&quot;-1&quot;&gt;What’s up with the &lt;code&gt;[Install]&lt;/code&gt; section?&lt;/h3&gt;
&lt;p&gt;You may have noticed that &lt;code&gt;Wants=&lt;/code&gt; and &lt;code&gt;Requires=&lt;/code&gt; appear in the &lt;code&gt;[Unit]&lt;/code&gt; section of a
unit file, while &lt;code&gt;WantedBy=&lt;/code&gt; and &lt;code&gt;RequiredBy=&lt;/code&gt; belong in the &lt;code&gt;[Install]&lt;/code&gt; section. Why?
And what does “install” even mean here?&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;[Install]&lt;/code&gt; section defines what happens when you &lt;strong&gt;enable&lt;/strong&gt; a unit (i.e., configure
it to auto-start at boot). So when you run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;systemctl enable tailscaled.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;systemd reads the &lt;code&gt;[Install]&lt;/code&gt; section, finds the &lt;code&gt;WantedBy=multi-user.target&lt;/code&gt;, and adds
the Tailscale service to the dependency list of the &lt;code&gt;multi-user.target&lt;/code&gt; unit.&lt;/p&gt;
&lt;p&gt;This is how auto-starting works: systemd already plans to activate &lt;code&gt;multi-user.target&lt;/code&gt;
during every boot process, and since Tailscale is now included as a dependency, the
service starts along with it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;[Install]&lt;/code&gt; section has no effect until you enable the service. Before
enabling, the unit exists, but the dependency relationship isn’t set up.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;why-you-need-before%3D-and-after%3D&quot; tabindex=&quot;-1&quot;&gt;Why You Need &lt;code&gt;Before=&lt;/code&gt; and &lt;code&gt;After=&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; &lt;code&gt;Wants=&lt;/code&gt;, &lt;code&gt;Requires=&lt;/code&gt;, and similar directives do &lt;strong&gt;not&lt;/strong&gt; control startup
order. They ensure that certain units are started &lt;em&gt;together&lt;/em&gt; in the same transaction,
but not necessarily in any particular sequence. systemd may still start your unit in
parallel with its dependencies.&lt;/p&gt;
&lt;p&gt;If you need your unit to start only &lt;em&gt;after&lt;/em&gt; another unit has reached an active (or
failed) state, you must explicitly use &lt;code&gt;After=&lt;/code&gt;. Similarly, if your unit must start
&lt;em&gt;before&lt;/em&gt; another, use &lt;code&gt;Before=&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Also note: &lt;code&gt;Before=&lt;/code&gt; and &lt;code&gt;After=&lt;/code&gt; do &lt;strong&gt;not&lt;/strong&gt; imply a dependency. If systemd wasn’t
already planning to start the referenced unit, these directives have no effect. They
only matter when the other unit is part of the current activation transaction.&lt;/p&gt;
&lt;p&gt;That’s why &lt;code&gt;Wants=&lt;/code&gt; or &lt;code&gt;Requires=&lt;/code&gt; are often paired with &lt;code&gt;After=&lt;/code&gt;. In most real-world
cases, you need both:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;dependency&lt;/strong&gt; (to pull the other unit into the current transaction),&lt;/li&gt;
&lt;li&gt;And an &lt;strong&gt;ordering constraint&lt;/strong&gt; (to control when it starts during the transaction).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-tailscale-example&quot; tabindex=&quot;-1&quot;&gt;The Tailscale Example&lt;/h2&gt;
&lt;p&gt;In the Tailscale example, you see this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;[Unit]
Wants=network-pre.target
After=network-pre.target NetworkManager.service systemd-resolved.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s what this configuration does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Wants=network-pre.target&lt;/code&gt;: Tailscale will start alongside &lt;code&gt;network-pre.target&lt;/code&gt;. If,
for some reason, you manually start &lt;code&gt;tailscaled.service&lt;/code&gt; and &lt;code&gt;network-pre.target&lt;/code&gt;
hasn’t been activated yet, systemd will try to activate it (and its dependencies)
as well.
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;network-pre.target&lt;/code&gt; fails, that’s acceptable — Tailscale still starts, because
it’s a soft dependency.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;After=...&lt;/code&gt;: Ensures Tailscale starts only &lt;em&gt;after&lt;/em&gt; &lt;code&gt;network-pre.target&lt;/code&gt;,
&lt;code&gt;NetworkManager.service&lt;/code&gt;, and &lt;code&gt;systemd-resolved.service&lt;/code&gt; have reached a final state
(either “active” or “failed”).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notice that &lt;code&gt;NetworkManager.service&lt;/code&gt; and &lt;code&gt;systemd-resolved.service&lt;/code&gt; are not
listed in &lt;code&gt;Wants=&lt;/code&gt;. That’s because Tailscale doesn’t want to &lt;em&gt;depend&lt;/em&gt; on them —
Tailscale can move mountains to &lt;a href=&quot;https://tailscale.com/blog/sisyphean-dns-client-linux&quot;&gt;handle all kinds of Linux DNS and networking configurations&lt;/a&gt;.
The unit file only ensures the Tailscale service starts after those services, &lt;strong&gt;if&lt;/strong&gt;
they are part of the current activation sequence.&lt;/p&gt;
&lt;p&gt;You’ll also see this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means that when &lt;code&gt;multi-user.target&lt;/code&gt; is activated (e.g., at boot), systemd will
also start &lt;code&gt;tailscaled.service&lt;/code&gt; — but only if you’ve previously run &lt;code&gt;systemctl enable tailscaled.service&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Section&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Wants=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[Unit]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Soft dependency: start together, ignore failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Requires=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[Unit]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hard dependency: start together, fail if dependency fails&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Before=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[Unit]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start this unit before the listed ones&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;After=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[Unit]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start this unit after the listed ones&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WantedBy=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[Install]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable auto-start by adding to another unit’s wants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RequiredBy=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[Install]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same, but with hard dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Rules of thumb&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;For most cases…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;Wants=&lt;/code&gt; + &lt;code&gt;After=&lt;/code&gt; together when you want a service to start after another
service or target.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;WantedBy=multi-user.target&lt;/code&gt; in the &lt;code&gt;[Install]&lt;/code&gt; section for services that you want
to auto-start on boot.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Tools like &lt;code&gt;systemd-analyze&lt;/code&gt; and &lt;code&gt;systemctl list-dependencies&lt;/code&gt; let you inspect
various parts of the dependency graph. On a typical desktop Linux system, the full
dependency graph is &lt;em&gt;huge&lt;/em&gt;. &lt;a href=&quot;https://philcrockett.com/notes/2026/01/25/systemd-targets-and-dependencies/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Sun, 25 Jan 2026 14:46:44 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2026/01/25/systemd-targets-and-dependencies/</guid>
    </item>
    <item>
      <title>iPhone: Two Months In</title>
      <link>https://philcrockett.com/notes/2026/01/16/iphone-after-two-months/</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/11/13/iphone/&quot;&gt;I bought an iPhone two months ago.&lt;/a&gt; So far, it seems like a
good decision.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;My phone screen time has gone down to an average of less than 1 hour per day.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2026/01/16/iphone-after-two-months/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;I’m surprised at how far I can get without any App Store downloads.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2026/01/16/iphone-after-two-months/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;I have yet to activate iCloud.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2026/01/16/iphone-after-two-months/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt; It (pleasantly) surprises me that Apple allows this
to be optional.&lt;/li&gt;
&lt;li&gt;Automation via the Shortcuts app is pretty great.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2026/01/16/iphone-after-two-months/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I thought it would be more of a struggle to resist the pull of Apple’s ecosystem, but
so far I haven’t had any problems keeping Apple at arm’s length despite owning one of
their devices.&lt;/p&gt;
&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Of course my laptop screen time has gone &lt;em&gt;up&lt;/em&gt; significantly, but that was the
intended effect. One of my goals was to get out of the mobile ecosystem as much as
possible and spend more time on devices I control. &lt;a href=&quot;https://philcrockett.com/notes/2026/01/16/iphone-after-two-months/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;You can setup Fastmail with minimal effort using iOS-native mail, calendar, and
reminders apps. iOS’s support for open standards like iCAL is surprisingly great
out-of-the-box. I &lt;em&gt;have&lt;/em&gt; downloaded a few apps, but so far haven’t needed to buy any. &lt;a href=&quot;https://philcrockett.com/notes/2026/01/16/iphone-after-two-months/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Backing things up encourages me to feel like my device is “safe” and can be
relied upon, which increases dependence. The whole goal of this experiment is to avoid
dependence on the mobile ecosystem as much as possible, so I avoid backup solutions
like iCloud intentionally. So far the only backup I have needed is for photos and
videos, that that is handled by &lt;a href=&quot;https://ente.io/&quot;&gt;Ente&lt;/a&gt;. &lt;a href=&quot;https://philcrockett.com/notes/2026/01/16/iphone-after-two-months/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Example: My phone automatically turns airplane mode on and off when I join or
leave a Wi-Fi network. My battery likes this; staying connected to cell towers sucks
a huge amount of battery life compared to Wi-Fi. Since Wi-Fi calling works &lt;em&gt;reliably&lt;/em&gt;
on iOS, I now have a nearly seamless way to remain connected, while increasing battery
longevity. &lt;a href=&quot;https://philcrockett.com/notes/2026/01/16/iphone-after-two-months/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Fri, 16 Jan 2026 05:26:54 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2026/01/16/iphone-after-two-months/</guid>
    </item>
    <item>
      <title>iPhone</title>
      <link>https://philcrockett.com/notes/2025/11/13/iphone/</link>
      <description>&lt;p&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; If you’re going for lowest total cost of ownership, iPhone will serve you
better than Android or its derivative operating systems. You’ll have to sacrifice
your software freedom, but then again… maybe we never had much freedom in any mobile
ecosystem in the first place.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;As a freedom-loving FOSS nerd, my mobile device of choice has traditionally been
Android-based. In particular, I have been very happy using a Pixel 5a with &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And then the phone died. And I’m frustrated that the total cost of ownership (TCO) for
that old phone (it was already old when I bought it) was 11 Euros per month.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/11/13/iphone/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;If you are fine with upgrading your mobile device every 2 years, then Android is
compelling. You’re going to be dropping a lot of cash on phones this way, so you might
as well buy the cheaper devices.&lt;/p&gt;
&lt;p&gt;However if your goal is to avoid using your mobile device as much as possible, and you
want to spend as little money as possible on this horrible&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/11/13/iphone/#fn1&quot; id=&quot;fnref1:1&quot;&gt;[1:1]&lt;/a&gt;&lt;/sup&gt; ecosystem… Android
makes zero sense. While iPhones may be more expensive up front, they offer better
hardware and longer software support. Apple devices are useable &lt;em&gt;in practice&lt;/em&gt; for twice
as long as their equivalent Android devices, yet do &lt;em&gt;not&lt;/em&gt; cost twice as much.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/11/13/iphone/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;So today I bought a refurbished iPhone 13 mini with a new battery. Along with a case
and screen protector, it cost around 300 Euros. This is a 4-year-old phone. If I can get
it to last another 4 years (until 2029) (with perhaps one battery replacement), I can
expect TCO to be around 7 Euros per month. My stretch goal will be to get it to last 6
years, bringing TCO down to less than 5 Euros per month.&lt;/p&gt;
&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I like to think of mobile device ownership cost in per-month terms. It makes it
feel like a subscription. However since basically everyone &lt;em&gt;needs&lt;/em&gt; a mobile device
in order to function in modern society, it’s more like a tax than a subscription. And
most of those taxes go directly to either Google or Apple. &lt;a href=&quot;https://philcrockett.com/notes/2025/11/13/iphone/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt; &lt;a href=&quot;https://philcrockett.com/notes/2025/11/13/iphone/#fnref1:1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Of course if you go the iPhone route, you’re giving away a lot of software
freedom and replacing it with a walled garden. Though honestly folks, if you want
&lt;em&gt;reasonably-priced&lt;/em&gt; software freedom, Android (including its derivatives) isn’t
the place to go. The mobile ecosystem is broken, and will stay broken until our
governments figure out a way to uproot this insane Google / Apple duopoly. Choose a
device that gives you a reasonable degree of privacy, use it when you’re forced to,
and get back to a Linux device for everything else. &lt;a href=&quot;https://philcrockett.com/notes/2025/11/13/iphone/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Thu, 13 Nov 2025 11:40:08 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2025/11/13/iphone/</guid>
    </item>
    <item>
      <title>PIPESTATUS</title>
      <link>https://philcrockett.com/notes/2025/10/20/pipestatus/</link>
      <description>&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; Bash’s &lt;code&gt;$PIPESTATUS&lt;/code&gt; allows you to inspect the exit status of every command
in a pipeline.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;According to Bash’s manpage, &lt;code&gt;$PIPESTATUS&lt;/code&gt; is…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An array variable… containing a list of exit status values from the commands in
the most-recently-executed foreground pipeline, which may consist of only a simple
command… Bash sets PIPESTATUS after executing multi-element pipelines, timed and
negated pipelines, simple commands, subshells created with the ( operator, the [[ and
(( compound commands, and after error conditions that result in the shell aborting
command execution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So it’s almost like &lt;code&gt;$?&lt;/code&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/10/20/pipestatus/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; on steroids. Especially useful when using the &lt;code&gt;yes&lt;/code&gt;
command&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/10/20/pipestatus/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; with interactive commands.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;set -o pipefail
yes | some_interactive_command
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code&gt;some_interactive_command&lt;/code&gt; closes its stdin stream while &lt;code&gt;yes&lt;/code&gt; is trying to write to
it (which is not uncommon), &lt;code&gt;yes&lt;/code&gt; will exit with an exit status of 141. Since we ran
&lt;code&gt;set -o pipefail&lt;/code&gt;, that will crash the script (even though &lt;code&gt;some_interactive_command&lt;/code&gt;
may have exited with status 0 “success”).&lt;/p&gt;
&lt;p&gt;Let’s modify the script a bit:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;set -o pipefail
yes | some_interactive_command || {
  echo &amp;quot;Exited with status $?&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows the script to keep running, but… sadly it reports the exit status of
&lt;code&gt;yes&lt;/code&gt;, rather than &lt;code&gt;some_interactive_command&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Exited with status 141&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That’s almost never what you want. Nobody cares about &lt;code&gt;yes&lt;/code&gt;. We only care about the
interactive command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;set -o pipefail
yes | some_interactive_command || {
  echo &amp;quot;Programs in the pipeline exited with these exit statuses: ${PIPESTATUS[*]}&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we’ll see this output:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Programs in the pipeline exited with these exit statuses: 141 0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;yes&lt;/code&gt; exited with status 141&lt;/li&gt;
&lt;li&gt;&lt;code&gt;some_interactive_command&lt;/code&gt; exited with status 0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So taking it just one step further…&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;set -o pipefail
yes | some_interactive_command || {
  echo &amp;quot;Exited with status ${PIPESTATUS[1]}&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Exited with status 0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That’s more like it. Now we’re looking at the exit status of the command we actually
care about. Putting it in a real-world script could look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;set -o pipefail

panic() {
  echo &amp;quot;$*&amp;quot; &amp;gt;&amp;amp;2
  exit 1
}

yes | some_interactive_command || {
  result=${PIPESTATUS[1]}
  test ${result} -eq 0 || panic &amp;quot;some_interactive_command exited with status ${result}&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;code&gt;$?&lt;/code&gt; expands to the exit status of the most recently used command &lt;a href=&quot;https://philcrockett.com/notes/2025/10/20/pipestatus/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;code&gt;yes&lt;/code&gt; (&lt;a href=&quot;https://man.archlinux.org/man/yes.1.en&quot;&gt;manpage&lt;/a&gt;) is super handy for
answering “yes / no” prompts in interactive commands. By default it just writes &lt;code&gt;y&lt;/code&gt;
to stdout over and over, which is usually enough to get through all those prompts, and
effectively makes an interactive command suitable for scripting. &lt;a href=&quot;https://philcrockett.com/notes/2025/10/20/pipestatus/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Mon, 20 Oct 2025 16:27:54 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2025/10/20/pipestatus/</guid>
    </item>
    <item>
      <title>tmpshell</title>
      <link>https://philcrockett.com/notes/2025/10/16/tmpshell/</link>
      <description>&lt;p&gt;I wrote a &lt;a href=&quot;https://github.com/pcrockett/lappy/blob/37f852c69ac68037011bc016d90782f2a16e827d/config/fish/functions/tmpshell.fish&quot;&gt;handy fish function&lt;/a&gt;
for those times when you just want to go to a temporary directory, mess with some files
and environment variables, and then clean up afterward:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# in ~/.config/fish/functions/tmpshell.fish
function tmpshell
  set temp_dir (mktemp --directory)
  cd $temp_dir
  echo &amp;quot;Run `exit` when finished&amp;quot;
  fish
  cd -
  rm -rf $temp_dir
  echo &amp;quot;Cleaned up $temp_dir&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s what an interactive session looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.config/fish/functions on  main [!]
❯ tmpshell
Run `exit` when finished
direnv: unloading

/tmp/tmp.rkxc5HRMOM
❯ echo &amp;quot;foo&amp;quot; &amp;gt; foo.txt

/tmp/tmp.rkxc5HRMOM
❯ exit
Cleaned up /tmp/tmp.rkxc5HRMOM

.config/fish/functions on  main [!] took 6s
❯
&lt;/code&gt;&lt;/pre&gt;
</description>
      <pubDate>Thu, 16 Oct 2025 04:49:59 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2025/10/16/tmpshell/</guid>
    </item>
    <item>
      <title>Google clicks on GitHub notifications for you</title>
      <link>https://philcrockett.com/notes/2025/10/11/google-clicks-on-github-notifications/</link>
      <description>&lt;p&gt;At work I use GitHub notifications heavily. However lately I’ve been noticing a strange
/ annoying phenomenon: GitHub notifications randomly mark themselves as “read” without
me looking at them. This is actually quite disruptive to my workflow, since I use the
“read” status to determine what things haven’t yet gotten my attention.&lt;/p&gt;
&lt;p&gt;After a long time trying to figure out what the problem was, I finally found &lt;a href=&quot;https://github.com/orgs/community/discussions/144794&quot;&gt;a GitHub
discussion&lt;/a&gt; including people who
experience the same issue. Apparently this has been happening for a while, but for some
reason I haven’t been falling victim to it until now.&lt;/p&gt;
&lt;p&gt;In short: I have notification emails set up in GitHub. Notification emails contain
tracking pixels. Once a tracking pixel is downloaded, the notification is marked as
read. Since Gmail&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/10/11/google-clicks-on-github-notifications/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; automatically downloads email contents like tracking pixels &lt;em&gt;upon
reciept&lt;/em&gt; (rather than when opening the email), notifications will often be marked as
read before I ever get the chance to see them.&lt;/p&gt;
&lt;p&gt;This is a good example of a problem that’s hard to troubleshoot, but easy to fix. You
have two options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Disable email notifications at &lt;a href=&quot;https://github.com/settings/notifications&quot;&gt;https://github.com/settings/notifications&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Get an email provider that doesn’t prefetch all your email contents.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;sadly, my &lt;em&gt;work&lt;/em&gt; email provider 😭 &lt;a href=&quot;https://philcrockett.com/notes/2025/10/11/google-clicks-on-github-notifications/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Sat, 11 Oct 2025 13:59:25 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2025/10/11/google-clicks-on-github-notifications/</guid>
    </item>
    <item>
      <title>Kudos to the Fish Devs</title>
      <link>https://philcrockett.com/notes/2025/03/04/fish-kudos/</link>
      <description>&lt;p&gt;Just look at &lt;a href=&quot;https://github.com/fish-shell/fish-shell/releases/tag/4.0.0&quot;&gt;this monumental feat&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I gotta say, the dev team behind fish really seems to know how to dev. They:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pulled off a rewrite&lt;/li&gt;
&lt;li&gt;care enough about their users to…
&lt;ul&gt;
&lt;li&gt;keep track of breaking changes and communicate them in great detail&lt;/li&gt;
&lt;li&gt;understand when to break things vs deprecate them&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;value POSIX compatibility while at the same time not allowing POSIX to ruin their
project&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;etc.&lt;/p&gt;
&lt;p&gt;Of course we’ll see for sure how well it turns out after a few point releases, but so
far at least, it seems like they deserve a standing ovation. I wonder how old they are,
because it looks to me like they have a lot of hard-won experience and discernment.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/03/04/fish-kudos/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I originally posted this on a &lt;a href=&quot;https://lobste.rs/s/ym7xhm/release_fish_shell_4_0_0_now_ported_rust#c_qavfls&quot;&gt;lobste.rs thread&lt;/a&gt;. However lately I have
started wanting to “own my words,” so I decided to duplicate the post here. &lt;a href=&quot;https://philcrockett.com/notes/2025/03/04/fish-kudos/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Tue, 04 Mar 2025 20:28:01 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2025/03/04/fish-kudos/</guid>
    </item>
    <item>
      <title>Tiny Tools: fztotp</title>
      <link>https://philcrockett.com/notes/2025/02/23/tiny-tools-fztotp/</link>
      <description>&lt;p&gt;&lt;em&gt;This is my first &lt;a href=&quot;https://philcrockett.com/notes/2024/06/29/tiny-tools/&quot;&gt;Tiny Tools&lt;/a&gt; post.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fztotp&lt;/code&gt; (“fuzzy TOTP”) is a relatively simple tool built on top of &lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;&lt;code&gt;fzf&lt;/code&gt;&lt;/a&gt; (as
are all of my most useful scripts) and &lt;a href=&quot;https://docs.yubico.com/software/yubikey/tools/ykman/intro.html&quot;&gt;&lt;code&gt;ykman&lt;/code&gt;&lt;/a&gt;. I’m a little biased, but
this is the best &lt;a href=&quot;https://en.wikipedia.org/wiki/Time-based_one-time_password&quot;&gt;TOTP&lt;/a&gt; authenticator app I have ever used (though it’s only for
&lt;a href=&quot;https://www.yubico.com/&quot;&gt;Yubikey&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;You can find the script &lt;a href=&quot;https://github.com/pcrockett/rush-repo/blob/main/fztotp/fztotp&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Its job is quite simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Show the list of TOTP auth credentials you have stored in your Yubikey, in an &lt;code&gt;fzf&lt;/code&gt;
user interface&lt;/li&gt;
&lt;li&gt;allow the user to fuzzy-select one of the credentials in the list, and then&lt;/li&gt;
&lt;li&gt;copy the TOTP code for that site to your clipboard (if you have
&lt;a href=&quot;https://github.com/kfish/xsel&quot;&gt;&lt;code&gt;xsel&lt;/code&gt;&lt;/a&gt; installed).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This enables me to get through multi-factor auth dialogs in just a few keystrokes. All
with just ~50 lines of code.&lt;/p&gt;
&lt;p&gt;If you have &lt;code&gt;fzf&lt;/code&gt; and &lt;code&gt;ykman&lt;/code&gt; installed already, you can install &lt;code&gt;fztotp&lt;/code&gt; on a Linux
machine with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -SsfL https://philcrockett.com/yolo/v1.sh &#92;
    | bash -s -- fztotp
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;comments%3F&quot; tabindex=&quot;-1&quot;&gt;Comments?&lt;/h2&gt;
&lt;p&gt;If you have a &lt;a href=&quot;https://joinmastodon.org/&quot;&gt;Mastodon&lt;/a&gt; account, you can reply to &lt;a href=&quot;https://fosstodon.org/@pcrock/114058031613011373&quot;&gt;my post on the Fediverse&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Sun, 23 Feb 2025 18:32:10 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2025/02/23/tiny-tools-fztotp/</guid>
    </item>
    <item>
      <title>FOSDEM N00b Tips</title>
      <link>https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/</link>
      <description>&lt;p&gt;So this year (2025) was my first year to visit &lt;a href=&quot;https://fosdem.org/&quot;&gt;FOSDEM&lt;/a&gt;. It was
also my first time in Belgium. I started writing down these tips as I learned them.
&lt;em&gt;If you are more experienced and you want to correct anything here, please do
&lt;a href=&quot;https://philcrockett.com/contact/&quot;&gt;let me know&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;preparing-for-fosdem&quot; tabindex=&quot;-1&quot;&gt;Preparing for FOSDEM&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;If you’re an Android person, install
&lt;a href=&quot;https://f-droid.org/packages/be.digitalia.fosdem/&quot;&gt;FOSDEM Companion&lt;/a&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; and start
bookmarking tracks you’re interested in. That will come in handy on FOSDEM day, trust
me.&lt;/li&gt;
&lt;li&gt;If you can, pack your own lunch and bring it with you to the conference. The food
trucks are ok, but expect to pay 10 EUR for lunch, and the lines get &lt;em&gt;really&lt;/em&gt; long
around lunchtime.&lt;/li&gt;
&lt;li&gt;Bring a water bottle and snack while you’re at it.&lt;/li&gt;
&lt;li&gt;You can pay for pretty much everything you need by card when you get to Brussels, if
you don’t want to carry much cash. Even the food trucks at FOSDEM accept cards.&lt;/li&gt;
&lt;li&gt;FOSDEM is a conference with a lot of people packed into small spaces. Bring a face
mask and hand sanitizer. As they said during the opening talk, “FOSDEM Flu is real.”&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;getting-to-the-conference&quot; tabindex=&quot;-1&quot;&gt;Getting to the conference&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;FOSDEM has a page with instructions to get to the conference, and
it’s really good high-level information. For the 2025 conference it was
&lt;a href=&quot;https://fosdem.org/2025/practical/transportation/&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you’re coming from the airport, there are kiosks where you can buy train
tickets&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;. A ticket to the central train station (Bruxelles Centraal) cost me about
11 EUR.&lt;/li&gt;
&lt;li&gt;The busses to the university are packed with FOSDEM attendees. If you get hot or
claustrophobic, take off your coat before you get on the bus. It gets warm and cozy.&lt;/li&gt;
&lt;li&gt;The easiest way to pay the bus fare is to swipe a bank card on the contactless
payment doodad thingy. You don’t even need to talk to the bus driver or push any
buttons. Just swipe your card.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;at-the-conference&quot; tabindex=&quot;-1&quot;&gt;At the conference&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;If you see a ridiculously long line when you arrive at the university first thing
in the morning, it’s &lt;strong&gt;not&lt;/strong&gt; for registration.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt; Instead, it’s probably a line
for buying t-shirts and hoodies. They are apparently very high-demand, especially
in the morning because they will run out of certain sizes later. So I &lt;em&gt;do&lt;/em&gt; recommend
standing in that line… if buying some swag is important to you.&lt;/li&gt;
&lt;li&gt;The lines for coffee in the morning are long. If you can bring your own, do it. &lt;em&gt;Or
alternatively use the long lines as an opportunity to get into conversations with
other fellow nerds.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Show up at rooms early. They often reach full capacity long before the talk
starts.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fn5&quot; id=&quot;fnref5&quot;&gt;[5]&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;If you’re interested in a talk that’s being given by a relatively famous person,
you may need to get into the room for the &lt;em&gt;preceeding talk&lt;/em&gt; &lt;strong&gt;before&lt;/strong&gt; the one you’re
actually interested in.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fn6&quot; id=&quot;fnref6&quot;&gt;[6]&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;leaving-brussels&quot; tabindex=&quot;-1&quot;&gt;Leaving Brussels&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;If you’re flying out of Brussels, I saw &lt;strong&gt;one&lt;/strong&gt; place to fill up a water bottle
for free after you’ve been through security. It’s at gate A43, labelled “free water
refills.” It’s in an area where there are other signs for overpriced airport food and
beverages, so it’s easy to miss if you don’t know it’s there.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;other-tips&quot; tabindex=&quot;-1&quot;&gt;Other tips&lt;/h2&gt;
&lt;p&gt;I’m not the first person to produce content like this on the Internet. A quick search,
for example, yielded &lt;a href=&quot;https://pothix.com/fosdem-guide/&quot;&gt;this very good first-timer FOSDEM guide&lt;/a&gt;
which has more useful information. I’m sure there are plenty of others.&lt;/p&gt;
&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;FOSDEM recommends this app, and others, on their
&lt;a href=&quot;https://fosdem.org/2025/schedule/mobile/&quot;&gt;mobile schedule apps page&lt;/a&gt;. &lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Public transport is a good way to get around, but there are things like taxis as
well. I’ve never used those, but I bet they’re expensive. &lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Concerningly, I don’t actually know how much I paid because it didn’t show me
a price… &lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;FOSDEM doesn’t require you to register, check in, or anything like that. &lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn5&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;FOSDEM staff is really good and strict about room capacity. Some rooms allow
people to stand or sit along the walls when all the seats fill up, but others have
a strict max capacity that is enforced, and there will be staff at the door to
prevent people from coming inside when that max capacity has filled up. &lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fnref5&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn6&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;For example, during FOSDEM 2025 most of the people in the Security room just
stayed in their seats after one particular talk, which means only a handful of
people in the hallway got in to hear &lt;a href=&quot;https://daniel.haxx.se/&quot;&gt;Daniel Steinberg&lt;/a&gt;
speak. &lt;a href=&quot;https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/#fnref6&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Mon, 03 Feb 2025 09:00:00 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2025/02/01/fosdem-noob-tips/</guid>
    </item>
    <item>
      <title>Tiny Tools</title>
      <link>https://philcrockett.com/notes/2024/06/29/tiny-tools/</link>
      <description>&lt;p&gt;A couple years ago I wrote about &lt;a href=&quot;https://philcrockett.com/notes/2022/12/17/dream-programming-language/&quot;&gt;what I want in a programming language&lt;/a&gt;.
I then decided to &lt;a href=&quot;https://philcrockett.com/notes/2022/12/27/trying-ocaml/&quot;&gt;try OCaml&lt;/a&gt; even though it was missing a few
important points in my list of requirements for a “dream language.” I never took OCaml much farther
than an over-engineered Hello World test run, though I did generally enjoy the experience.&lt;/p&gt;
&lt;p&gt;I was looking for a good load-bearing language – something that scales well, makes a large codebase
easy &lt;strong&gt;and&lt;/strong&gt; enjoyable to maintain, and which you could use to build big tools or systems with. In
hindsight, I should have been looking for a language that makes it easy and fun to create &lt;em&gt;tiny
tools&lt;/em&gt;. Since I have a small child and other priorities, I don’t have too much time or energy to
build big things, and I’m ok with that.&lt;/p&gt;
&lt;p&gt;Which is why since then I have mostly been enjoying Bash and Nushell.&lt;/p&gt;
&lt;h2 id=&quot;nushell&quot; tabindex=&quot;-1&quot;&gt;Nushell&lt;/h2&gt;
&lt;p&gt;I don’t recommend &lt;a href=&quot;https://www.nushell.sh/&quot;&gt;Nushell&lt;/a&gt; as your day-to-day interactive shell (yet). But
writing small scripts in Nushell is insanely fun. I like the syntax, type safety, functional style.
I like the polish around displaying things, parameter parsing, help messages, and JSON parsing. I
like how it encourages you to create a sort of well-defined data flow and transformation pipeline in
your scripts.&lt;/p&gt;
&lt;p&gt;It makes me happy.&lt;/p&gt;
&lt;p&gt;But I really only use it for personal scripts, because it hasn’t reached a stable 1.0 yet and not
many people have it installed. I’ve also had trouble using it seriously with programs like
&lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;fzf&lt;/a&gt;, which I also love.&lt;/p&gt;
&lt;p&gt;So for everything else, there’s…&lt;/p&gt;
&lt;h2 id=&quot;bash%3F-srsly%3F&quot; tabindex=&quot;-1&quot;&gt;Bash? srsly?&lt;/h2&gt;
&lt;p&gt;I never thought I would say this, but Bash is actually &lt;em&gt;really fun&lt;/em&gt;. I’ve gotten quite good at it.
Don’t get me wrong: It is a terrible, horrible, no-good language for &lt;em&gt;a lot&lt;/em&gt; of use cases. But it
is still incredibly good at gluing bigger programs together in interesting ways with very few lines
of code.&lt;/p&gt;
&lt;p&gt;It’s also &lt;em&gt;shippable&lt;/em&gt; – I can publish Bash scripts with an open source license, and other people
might actually benefit from them. I’ve developed a certain style in writing Bash that makes the
code surprisingly bearable to read, more robust, and avoids a lot of common landmines.&lt;/p&gt;
&lt;p&gt;In other words, Bash allows me to leverage other people’s hard work with load-bearing languages to
solve my own problems using just a few lines of code.&lt;/p&gt;
&lt;h2 id=&quot;i%E2%80%99ll-write-more&quot; tabindex=&quot;-1&quot;&gt;I’ll write more&lt;/h2&gt;
&lt;p&gt;I’m trying to keep these posts short, and my son is starting to wake up. I’m gonna go hang out with
him. Perhaps later I’ll write a followup post about some of my Bash projects (which are mostly
published on GitHub) and some of the tools I find to be indispensable for making nice CLIs and
TUIs.&lt;/p&gt;
&lt;h2 id=&quot;comments%3F&quot; tabindex=&quot;-1&quot;&gt;Comments?&lt;/h2&gt;
&lt;p&gt;If you have a &lt;a href=&quot;https://joinmastodon.org/&quot;&gt;Mastodon&lt;/a&gt; account, you can reply to &lt;a href=&quot;https://fosstodon.org/deck/@pcrock/112698356732753269&quot;&gt;my post on the Fediverse&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Sat, 29 Jun 2024 05:09:20 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2024/06/29/tiny-tools/</guid>
    </item>
    <item>
      <title>2.4 GHz WiFi Trouble? Disable Bluetooth.</title>
      <link>https://philcrockett.com/notes/2023/06/22/wifi-trouble-disable-bluetooth/</link>
      <description>&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; Bluetooth and 2.4 GHz WiFi don’t play nicely together. Here’s how I figured it out.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I have both 2.4 and 5 GHz networks running in my home. I have found that my personal laptop has
a &lt;em&gt;really&lt;/em&gt; hard time scanning for / connecting to 2.4 GHz networks. It’ll eventually connect, but
it takes up to a few minutes to find the 2.4 GHz network and work out a connection.&lt;/p&gt;
&lt;p&gt;I got tired of it and started searching the Interwebz.&lt;/p&gt;
&lt;p&gt;At some point in my web searches, I learned that I’m running an Intel wireless network card using
the built-in Linux kernel &lt;code&gt;iwlwifi&lt;/code&gt; driver. &lt;em&gt;Here’s partial output of &lt;code&gt;lspci -k&lt;/code&gt;:&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;02:00.0 Network controller: Intel Corporation Wireless 8265 / 8275 (rev 78)
    Subsystem: Intel Corporation Wireless 8265 / 8275
    Kernel driver in use: iwlwifi
    Kernel modules: iwlwifi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also learned about the various config parameters for this driver. &lt;em&gt;Here’s partial output of
&lt;code&gt;modinfo iwlwifi&lt;/code&gt;:&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;parm:           swcrypto:using crypto in software (default 0 [hardware]) (int)
parm:           11n_disable:disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX (uint)
parm:           amsdu_size:amsdu size 0: 12K for multi Rx queue devices, 2K for AX210 devices, 4K for other devices 1:4K 2:8K 3:12K (16K buffers) 4: 2K (default 0) (int)
parm:           fw_restart:restart firmware in case of error (default true) (bool)
parm:           nvm_file:NVM file name (charp)
parm:           uapsd_disable:disable U-APSD functionality bitmap 1: BSS 2: P2P Client (default: 3) (uint)
parm:           enable_ini:0:disable, 1-15:FW_DBG_PRESET Values, 16:enabled without preset value defined,Debug INI TLV FW debug infrastructure (default: 16)
parm:           bt_coex_active:enable wifi/bt co-exist (default: enable) (bool)
parm:           led_mode:0=system default, 1=On(RF On)/Off(RF Off), 2=blinking, 3=Off (default: 0) (int)
parm:           power_save:enable WiFi power management (default: disable) (bool)
parm:           power_level:default power save level (range from 1 - 5, default: 1) (int)
parm:           disable_11ac:Disable VHT capabilities (default: false) (bool)
parm:           remove_when_gone:Remove dev from PCIe bus if it is deemed inaccessible (default: false) (bool)
parm:           disable_11ax:Disable HE capabilities (default: false) (bool)
parm:           disable_11be:Disable EHT capabilities (default: false) (bool)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well hey, what’s this &lt;code&gt;bt_coex_active:enable wifi/bt co-exist&lt;/code&gt; business? Some web searching led me
to &lt;a href=&quot;https://superuser.com/a/1118989&quot;&gt;this very old SuperUser answer&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The 2.4 GHz Wifi band and bluetooth spectrums have a great deal of overlap and can conflict with
each other&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So apparently you can configure your driver to not allow Bluetooth and 2.4 GHz WiFi to be activated
simultaneously, which can be important because their operating frequencies overlap.&lt;/p&gt;
&lt;p&gt;I don’t use (or like) Bluetooth anyway, so instead of messing with my driver, I just decided to turn
Bluetooth off permanently.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl disable --now bluetooth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Problem solved.&lt;/p&gt;
</description>
      <pubDate>Thu, 22 Jun 2023 19:20:42 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2023/06/22/wifi-trouble-disable-bluetooth/</guid>
    </item>
    <item>
      <title>SSH: Security Liability?</title>
      <link>https://philcrockett.com/notes/2023/01/22/ssh-security-liability/</link>
      <description>&lt;p&gt;SSH is pretty handy. As a hobbyist who actually &lt;em&gt;enjoys&lt;/em&gt; managing a few Linux boxes, I
use it all the time. However I can’t shake the feeling that it’s a significant security
liability for a server administrator, despite the fact that the first S in SSH stands
for “secure.”&lt;/p&gt;
&lt;p&gt;It has too much in common with projects like &lt;a href=&quot;https://latacora.micro.blog/2019/07/16/the-pgp-problem.html&quot;&gt;PGP / GPG&lt;/a&gt; and OpenVPN, which:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;were designed a &lt;em&gt;long&lt;/em&gt; time ago&lt;/li&gt;
&lt;li&gt;have huge C / C++ codebases&lt;/li&gt;
&lt;li&gt;are difficult to understand, configure, and use correctly&lt;/li&gt;
&lt;li&gt;make it really difficult to &lt;a href=&quot;https://blog.codinghorror.com/falling-into-the-pit-of-success/&quot;&gt;fall into the pit of success&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After all, if you need &lt;a href=&quot;https://github.com/jtesta/ssh-audit&quot;&gt;configuration auditing software&lt;/a&gt; and a myriad of
“hardening” guides on the Internet, then it just might be too complex.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2023/01/22/ssh-security-liability/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&quot;learning-from-wireguard&quot; tabindex=&quot;-1&quot;&gt;Learning From WireGuard&lt;/h2&gt;
&lt;p&gt;I’m not aware of any widely-used alternatives that are secure. But if the &lt;a href=&quot;https://www.wireguard.com/&quot;&gt;WireGuard&lt;/a&gt;
developers ever come up with something, it’ll probably be exactly what I’m looking for.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;WireGuard has been designed with ease-of-implementation and simplicity in mind. It
is meant to be easily implemented in very few lines of code, and easily auditable for
security vulnerabilities.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A great example of this is how WireGuard approaches versioning, which is exactly the
opposite of PGP, OpenVPN, and SSH:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;WireGuard restricts the options for implementing cryptographic controls, limits the
choices for key exchange processes, and maps algorithms to a small subset of modern
cryptographic primitives. If a flaw is found in any of the primitives, a new version
can be released that resolves the issue.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;small&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/WireGuard&quot;&gt;From Wikipedia&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-i-do&quot; tabindex=&quot;-1&quot;&gt;What I Do&lt;/h2&gt;
&lt;p&gt;I don’t bother with SSH configuration on my servers anymore. Instead, I rely on
&lt;a href=&quot;https://tailscale.com/&quot;&gt;Tailscale&lt;/a&gt; (which uses WireGuard) to connect to my servers. My firewall only allows
SSH access via the Tailscale interface. At this point I could &lt;em&gt;almost&lt;/em&gt; discard SSH
entirely and use &lt;a href=&quot;https://en.wikipedia.org/wiki/Telnet&quot;&gt;Telnet&lt;/a&gt; instead (though I don’t).&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2023/01/22/ssh-security-liability/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Of course I have the luxury of being a self-hosted hobbyist, so I don’t have a very
complex threat model, and this works well for me. I doubt if the same strategy would be
feasible for someone who needed to &lt;a href=&quot;https://goteleport.com/blog/how-uber-netflix-facebook-do-ssh/&quot;&gt;manage a bunch of servers at scale&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;comments%3F&quot; tabindex=&quot;-1&quot;&gt;Comments?&lt;/h2&gt;
&lt;p&gt;If you have a &lt;a href=&quot;https://joinmastodon.org/&quot;&gt;Mastodon&lt;/a&gt; account, you can reply to &lt;a href=&quot;https://fosstodon.org/@pcrock/109732805093391136&quot;&gt;my post on the Fediverse&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Though to be fair, you could make &lt;em&gt;exactly&lt;/em&gt; the same arguments about the Linux
kernel or any Linux distribution. I’m not 100% sure why I give the operating
system a pass, while being skeptical of SSH 🤔. &lt;a href=&quot;https://philcrockett.com/notes/2023/01/22/ssh-security-liability/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Splitting things into separate independent pieces (VPN + Telnet) would be a step
backward. See &lt;a href=&quot;https://www.leviathansecurity.com/blog/tunnelvision&quot;&gt;TunnelVision&lt;/a&gt; for an example of how this can go wrong. It would
be really cool if someone built an &lt;em&gt;&lt;strong&gt;integrated&lt;/strong&gt;&lt;/em&gt; SSH-like remote control mechanism
where the transport was basically WireGuard. &lt;a href=&quot;https://philcrockett.com/notes/2023/01/22/ssh-security-liability/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Sun, 22 Jan 2023 11:30:33 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2023/01/22/ssh-security-liability/</guid>
    </item>
    <item>
      <title>Trying OCaml</title>
      <link>https://philcrockett.com/notes/2022/12/27/trying-ocaml/</link>
      <description>&lt;p&gt;I used my &lt;a href=&quot;https://philcrockett.com/notes/2022/12/17/dream-programming-language/&quot;&gt;list of requirements for a “dream” programming language&lt;/a&gt;
to create a spreadsheet. I use that spreadsheet to calculate a score for each language
based on how well it fits my list of requirements.&lt;/p&gt;
&lt;p&gt;Two languages so far score the highest:&lt;/p&gt;
&lt;h2 id=&quot;gleam&quot; tabindex=&quot;-1&quot;&gt;Gleam&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://gleam.run/&quot;&gt;Gleam&lt;/a&gt; is &lt;em&gt;so close&lt;/em&gt; to what I’m looking for. It only misses one
mark: native executables&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://philcrockett.com/notes/2022/12/27/trying-ocaml/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. Gleam runs on the Erlang VM or compiles to JavaScript,
which is a showstopper for the kind of little hobby command line programs I want to
write. However if I ever decide to create a service that can be deployed to a server,
I’ll be super excited to try out Gleam.&lt;/p&gt;
&lt;h2 id=&quot;ocaml&quot; tabindex=&quot;-1&quot;&gt;OCaml&lt;/h2&gt;
&lt;p&gt;The next best contender I could find for the kind of software I want to write is
&lt;a href=&quot;https://ocaml.org/&quot;&gt;OCaml&lt;/a&gt;. I must say, I have never enjoyed writing / over-engineering
&lt;a href=&quot;https://github.com/pcrockett/hello-ocaml/&quot;&gt;a hello world program&lt;/a&gt; so much. The language
does sadly use exceptions for error handling, though thankfully exceptions are no longer
considered idiomatic.&lt;/p&gt;
&lt;p&gt;I’m going to continue playing with it. We’ll see where this goes.&lt;/p&gt;
&lt;h2 id=&quot;comments%3F&quot; tabindex=&quot;-1&quot;&gt;Comments?&lt;/h2&gt;
&lt;p&gt;If you have a &lt;a href=&quot;https://joinmastodon.org/&quot;&gt;Mastodon&lt;/a&gt; account, you can reply to &lt;a href=&quot;https://fosstodon.org/@pcrock/109587202658507764&quot;&gt;my post on the Fediverse&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Well, Gleam also misses the &lt;em&gt;object capabilities&lt;/em&gt; requirement, but almost all
other languages miss that feature as well. As of this writing, the few languages
that have object capabilities are in the experimental stage. &lt;a href=&quot;https://philcrockett.com/notes/2022/12/27/trying-ocaml/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Tue, 27 Dec 2022 18:44:34 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2022/12/27/trying-ocaml/</guid>
    </item>
    <item>
      <title>My Dream Programming Language</title>
      <link>https://philcrockett.com/notes/2022/12/17/dream-programming-language/</link>
      <description>&lt;p&gt;I’m on the hunt for a fun programming language that I can pick up and mess with in my free time. I
have a few fairly normal requirements that a lot of people ask for, plus a few less common
requirements. I don’t think this programming language exists as of 2022. If it does, do me a solid
and &lt;a href=&quot;https://philcrockett.com/contact/&quot;&gt;let me know&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id=&quot;the-usual-requirements&quot; tabindex=&quot;-1&quot;&gt;The Usual Requirements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Functional programming paradigm (primarily)&lt;/li&gt;
&lt;li&gt;Compiles to native, dependency-free executable
&lt;ul&gt;
&lt;li&gt;I could compromise on this if it were a small scripting language&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Robust type system&lt;/li&gt;
&lt;li&gt;Intuitive / enjoyable syntax&lt;/li&gt;
&lt;li&gt;Reasonable learning curve
&lt;ul&gt;
&lt;li&gt;While I like Rust, I’m looking for something &lt;a href=&quot;https://mdwdotla.medium.com/using-rust-at-a-startup-a-cautionary-tale-42ab823d9454&quot;&gt;with lower standards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;… but with &lt;a href=&quot;https://fasterthanli.me/articles/i-want-off-mr-golangs-wild-ride#simple-is-a-lie&quot;&gt;higher standards than Go&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Reasonably efficient performance-wise&lt;/li&gt;
&lt;li&gt;Open source&lt;/li&gt;
&lt;li&gt;Runs well on Linux (cross-platform a bonus)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-unusual-requirements&quot; tabindex=&quot;-1&quot;&gt;The Unusual Requirements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Uses &lt;a href=&quot;https://tutorial.ponylang.io/reference-capabilities/index.html&quot;&gt;object capabilities&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;no more static / global APIs for file, network, and other resources&lt;/li&gt;
&lt;li&gt;encourages &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_injection&quot;&gt;dependency injection&lt;/a&gt; instead&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.rust-lang.org/std/result/&quot;&gt;Result types&lt;/a&gt; instead of exceptions&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.rust-lang.org/std/option/&quot;&gt;Option types&lt;/a&gt; instead of nulls&lt;/li&gt;
&lt;li&gt;Robust &lt;a href=&quot;https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html&quot;&gt;pattern matching&lt;/a&gt; (important for the above two points)&lt;/li&gt;
&lt;li&gt;Doesn’t require a heavyweight IDE or excessively complex “new project” structure&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;comments%3F&quot; tabindex=&quot;-1&quot;&gt;Comments?&lt;/h2&gt;
&lt;p&gt;If you have a &lt;a href=&quot;https://joinmastodon.org/&quot;&gt;Mastodon&lt;/a&gt; account, you can reply to &lt;a href=&quot;https://fosstodon.org/@pcrock/109528890000674779&quot;&gt;my post on the Fediverse&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Sat, 17 Dec 2022 00:00:00 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2022/12/17/dream-programming-language/</guid>
    </item>
    <item>
      <title>What is this?</title>
      <link>https://philcrockett.com/notes/2022/11/07/</link>
      <description>&lt;p&gt;This is the beginning of my collection of notes.&lt;/p&gt;
&lt;p&gt;No, this is not a blog. I’ve tried maintaining a blog before, and always had trouble
keeping up with it or finding things to write. Instead, I hope to keep this all very
small and informal. It’s just a place to quickly dump my thoughts.&lt;/p&gt;
&lt;!-- lint disable maximum-line-length --&gt;
&lt;p&gt;Sure, I’ll use this to &lt;a href=&quot;https://jvns.ca/blog/2021/05/24/blog-about-what-you-ve-struggled-with/&quot;&gt;write about what I’ve struggled with&lt;/a&gt;,
or maybe I’ll turn it into a sort of &lt;a href=&quot;https://en.wikipedia.org/wiki/Zettelkasten&quot;&gt;Zettelkasten&lt;/a&gt;.
In any case, I &lt;strong&gt;do not&lt;/strong&gt; guarantee that these pages will stay around long-term or
remain immutable. I will edit or prune them whenever I feel like it.&lt;/p&gt;
&lt;!-- lint enable maximum-line-length --&gt;
</description>
      <pubDate>Mon, 07 Nov 2022 00:00:00 GMT</pubDate>
      <dc:creator>Phil Crockett</dc:creator>
      <guid>https://philcrockett.com/notes/2022/11/07/</guid>
    </item>
  </channel>
</rss>