<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>netizen.se blog</title><link>https://blog.netizen.se</link><description></description><item><title>Redirect ssh for Moved Repositories</title><link>https://blog.netizen.se/p/redirect-ssh-for-moved-repositories/</link><description><![CDATA[<p>While strong arguments can be made for creating resources with permanent paths,
making links to their location forever reachable, it is unavoidable and
sometimes desired to reorganize and move things around. This post is about
<a href="https://en.wikipedia.org/wiki/Git">git</a> repositories in particular.</p>
<p>For moved repositories accessed over http(s), there's <a href="https://http.cat/301">301 Moved
Permanently</a> (or <a href="https://en.wikipedia.org/wiki/HTTP_301">Wikipedia</a>), but when accessing using ssh no
similar functionality exist on a protocol level.  In at least my reality that
means redirects work for things where I only have read access, but not for
remotes which I also can push commits to. It might be theoretically possible to
setup write operations over https, but ssh is much more common.</p>
<p>As already stated, there simply is no way to get a machine readable redirect
for git over ssh. The approach here will write a banner to stderr, which ought
to be noticable enough for a human git user and hopefully good enough for many
cases.</p>
<p>The actual example code will focus on moves to some other directory on the same
server, but the same method could be applied to redirect to some completely
different server.</p>
<p>When git performs operations through an ssh server, it actually runs a bunch of
commands such as <a href="https://git-scm.com/docs/git-upload-pack"><code>git-upload-pack</code></a>. That is where one can output
a redirection message on <em>stderr</em> advising about the new location.</p>
<p>Start by creating <code>/etc/ssh/sshd_config.d/ssh_redir.conf</code> containing something
like:</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#c0c5ce;">Match User git
</span><span style="color:#c0c5ce;">    ForceCommand /opt/netizense/libexec/wrapper
</span></code></pre>
<p>Next, the referenced <code>wrapper</code> could look like:</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#65737e;">#!/bin/sh
</span><span style="color:#b48ead;">case </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#bf616a;">SSH_ORIGINAL_COMMAND</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#b48ead;">in
</span><span style="color:#c0c5ce;">  &#39;</span><span style="color:#a3be8c;">git-upload-pack </span><span style="color:#c0c5ce;">&#39;*</span><span style="color:#b48ead;">)
</span><span style="color:#c0c5ce;">    </span><span style="color:#bf616a;">_our_dir</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">( </span><span style="color:#8fa1b3;">dirname </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#bf616a;">0</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#a3be8c;">)</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">    </span><span style="color:#bf616a;">PATH</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#bf616a;">_our_dir</span><span style="color:#a3be8c;">:</span><span style="color:#c0c5ce;">$</span><span style="color:#bf616a;">PATH</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">    </span><span style="color:#b48ead;">export </span><span style="color:#bf616a;">PATH
</span><span style="color:#c0c5ce;">    </span><span style="color:#65737e;"># As git-shell ignores $PATH, sh is used here.
</span><span style="color:#c0c5ce;">    </span><span style="color:#96b5b4;">exec</span><span style="color:#c0c5ce;"> /bin/sh -c &quot;$</span><span style="color:#bf616a;">SSH_ORIGINAL_COMMAND</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">    ;;
</span><span style="color:#c0c5ce;">  &#39;&#39;</span><span style="color:#b48ead;">)
</span><span style="color:#c0c5ce;">    </span><span style="color:#96b5b4;">exec</span><span style="color:#c0c5ce;"> git-shell
</span><span style="color:#c0c5ce;">    ;;
</span><span style="color:#c0c5ce;">  *</span><span style="color:#b48ead;">)
</span><span style="color:#c0c5ce;">    </span><span style="color:#96b5b4;">exec</span><span style="color:#c0c5ce;"> git-shell -c &quot;$</span><span style="color:#bf616a;">SSH_ORIGINAL_COMMAND</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">    ;;
</span><span style="color:#b48ead;">esac
</span></code></pre>
<p>In plain language, the script checks whether a specific command is run. If that
is the case, it determines its own directory and adds that as the first of
<a href="https://en.wikipedia.org/wiki/PATH_(variable)"><code>$PATH</code></a>'s entries, which enables finding our own version of
git-upload-pack when executing that command. All other commands are executed
with git-shell as usual. The special handling of the no arguments case is to
for interactive shells.</p>
<p>Note that passing arguments to /bin/sh in this manner makes arbitrary command
execution possible. I trust all my git users with shell access, so its not a
problem on for me. Others might have different policies, thus requiring some
adaption to quote shell characters or patching the sources of the actual
git-upload-pack executable and recompiling it.</p>
<p>Here follows the script I use for <code>git-upload-pack</code>: (must be in the same
directory as <code>wrapper</code> for that $our_dir construct to work)</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#65737e;">#!/bin/sh -eu
</span><span style="color:#c0c5ce;">
</span><span style="color:#bf616a;">_git_dir</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">( </span><span style="color:#96b5b4;">eval</span><span style="color:#a3be8c;"> echo </span><span style="color:#c0c5ce;">&quot;</span><span style="color:#96b5b4;">\$</span><span style="color:#c0c5ce;">$</span><span style="color:#bf616a;">#</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#a3be8c;">)</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#bf616a;">_real_dir</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">( </span><span style="color:#8fa1b3;">realpath </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#bf616a;">_git_dir</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#a3be8c;">)</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#96b5b4;">[ </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#bf616a;">_real_dir</span><span style="color:#c0c5ce;">&quot; = &quot;$</span><span style="color:#bf616a;">_git_dir</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#96b5b4;">] </span><span style="color:#c0c5ce;">|| </span><span style="color:#96b5b4;">printf </span><span style="color:#c0c5ce;">&#39;</span><span style="color:#a3be8c;">%s\n%s\n\n%s\n\n%s\n%s\n</span><span style="color:#c0c5ce;">&#39; \
</span><span style="color:#c0c5ce;">        &#39;</span><span style="color:#a3be8c;">******************************************************************</span><span style="color:#c0c5ce;">&#39; \
</span><span style="color:#c0c5ce;">        &quot;</span><span style="color:#a3be8c;">Please note that </span><span style="color:#c0c5ce;">$</span><span style="color:#bf616a;">_git_dir</span><span style="color:#a3be8c;"> has moved to:</span><span style="color:#c0c5ce;">&quot; \
</span><span style="color:#c0c5ce;">        &quot;    $</span><span style="color:#bf616a;">_real_dir</span><span style="color:#c0c5ce;">&quot; \
</span><span style="color:#c0c5ce;">        &#39;</span><span style="color:#a3be8c;">Update your repository remote!</span><span style="color:#c0c5ce;">&#39; \
</span><span style="color:#c0c5ce;">        &#39;</span><span style="color:#a3be8c;">******************************************************************</span><span style="color:#c0c5ce;">&#39; \
</span><span style="color:#c0c5ce;">        &gt;&amp;</span><span style="color:#d08770;">2
</span><span style="color:#96b5b4;">unset</span><span style="color:#c0c5ce;"> _git_dir
</span><span style="color:#c0c5ce;">
</span><span style="color:#96b5b4;">exec</span><span style="color:#c0c5ce;"> git-shell -c &quot;$</span><span style="color:#bf616a;">SSH_ORIGINAL_COMMAND</span><span style="color:#c0c5ce;">&quot;
</span></code></pre>
<p>That script starts with getting the last argument (<code>\$$#</code>) which is directory
the git repository is in. It then checks whether it is (within) a symlink or
not. In case it is, the warning is printed on stderr. It then launches the
original command.</p>
<p>One can of course also add logging or what not to the wrapper script, but I
don't personally see a need for that. If doing so, one might want to look at
wrapping more (or all) git commands.</p>
<p>In order for these changes to actually bite, sshd needs to be restarted.</p>
]]></description><guid>https://blog.netizen.se/p/redirect-ssh-for-moved-repositories/</guid><pubDate>Sun, 24 Aug 2025 20:42:23 +0000</pubDate></item><item><title>Unspecific Perl Error</title><link>https://blog.netizen.se/p/unspecific-perl-error/</link><description><![CDATA[<p><strong>TL;DR</strong>: This was resolved by disabling my $PERL_LOCAL_LIB_ROOT folder. I
should have tried that earlier, instead of ruling it out just because the
seemingly failing module was not there.</p>
<p>Here are mostly merely my notes from a problem I encountered this morning. Not
really a proper blog post, but published anyway as I know at least one other
person has found it interesting.</p>
<h2>Problem description</h2>
<p>After upgrading one of my machines from OpenBSD 7.6 to <a href="https://www.openbsd.org/77.html">7.7</a> I could no
longer run (some of) my perl scripts. A trivial hello world script worked, but
this extremely stripped down version of an actual script didn't:</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#65737e;">#!/usr/bin/env perl
</span><span style="color:#c0c5ce;">
</span><span style="color:#b48ead;">use</span><span style="color:#c0c5ce;"> DateTime;
</span></code></pre>
<p>My expectation of running the above would be that it essentially should do
nothing. However what actually happened was that perl returned 1 and gave the
following error message as its output:</p>
<blockquote>
<p>XS.c: loadable library and perl binaries are mismatched (got first handshake
key 0xf280000, needed 0xf180000)</p>
</blockquote>
<p>That seems correct, but it is not phrased in a super-helpful way. Given that
the script only contains one line, I assumed that the mismatch was between perl
and the DateTime module. That one does indeed contain a .so-file which may
depend on the perl version. These were both installed the OpenBSD way. As
mentioned in the <a href="https://www.openbsd.org/77.html">release notes</a>, OpenBSD comes with version 5.40.1 of
Perl. On my system DateTime came from package p5-DateTime-1.66v0, installed
through ports using <code>pkg_add</code>.</p>
<h2>About the error message</h2>
<p>Today was not my first time to encounter this error message. I kind of knew
what it was all about, on some level. The devil is always in the details, and I
have not previously saved any notes. There is <a href="https://github.com/perl/perl5/issues/15861">an issue</a>, which I have
visited in the past and found again today. It is titled <em>"loadable library and
perl binaries are mismatched" not informative</em> and is a long-read. It now
appears to ended up in better error handling got added as recently as a couple
of weeks ago, with the merge of <a href="https://github.com/Perl/perl5/pull/22719">#22719</a>. Great news, for anyone
encountering this with a future version of Perl!</p>
<h2>Examining my system</h2>
<p>When I ran <code>pkg_info -v p5-DateTime-1.66v0 | grep signify</code> it appeared the
package (built 2025-04-11T19:55:16Z) was older than OpenBSD 7.7 (released April
28, 2025). I'm not fully understanding the release process though, so it is not
impossible the package was built for a release candidate or whatever. When
trying to analyze the package on technical merit, I got lost a little. These
however seem reasonble to guess having to do with ABI versioning or something:</p>
<blockquote>
<p>@wantlib c.100.3
@wantlib perl.25.0</p>
</blockquote>
<p>The only file installed by the package which seems to be affected by versions
is a shared library. Merely running <code>file</code> on it gave:</p>
<blockquote>
<p>/usr/local/libdata/perl5/site_perl/amd64-openbsd/auto/DateTime/DateTime.so: ELF 64-bit LSB shared object, x86-64, version 1</p>
</blockquote>
<p>Some comments to the existing bug report suggests examining which perl version
the object depends on using <code>ldd</code>. However attempting to do so on OpenBSD,
where the command takes no options, only gave:</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#c0c5ce;">/usr/local/libdata/perl5/site_perl/amd64-openbsd/auto/DateTime/DateTime.so:
</span><span style="color:#c0c5ce;">        Start            End              Type  Open Ref GrpRef Name
</span><span style="color:#c0c5ce;">        00000092cf403000 00000092cf40a000 dlib  1    0   0      /usr/local/libdata/perl5/site_perl/amd64-openbsd/auto/DateTime/DateTime.so
</span></code></pre>
<p>I'm uncertain of how to dig deeper in order to verify it is indeed the culprit.
One might suspect that perl is picking up a version of the module installed
with cpanm, perhaps? The output of running <code>find "$PERL_LOCAL_LIB_ROOT" -name "*DateTime*"</code> suggest that is not the case though. Maybe the packaged version
is actually in a broken state?</p>
<h2>Failed mitigation</h2>
<p>In an attempt to mitigate the issue, I did <code>pkg_delete p5-DateTime</code>, updated my
ports tree and ran <code>make install</code> in <em>devel/p5-DateTime</em>. The error message
about versions remained even after doing that, suggesting my hypothesis of the
port being to blame was faulty, and the issue to be a bit more complex than
what I hoped for.</p>
<h2>Successful resolution</h2>
<p>After running <code>mv "$PERL_LOCAL_LIB_ROOT" "$PERL_LOCAL_LIB_ROOT-$( date +%Y%m%d )"</code> the issue finally got resolved. In retrospect I should have tried this
sooner. Already knowing the DateTime module was not there, one now wonders what
the cause could be. Could it be that the DateTime module for some reason was
using a locally installed module for something which in some way got installed
in some other manner with the OpenBSD upgrade? Analyzing stuff just slightly
further, revealed that the failing module was <a href="https://metacpan.org/pod/Package::Stash::XS">Package::Stash::XS</a>. We
recognize XS from the error message. I have not went down the rabbit hole, but
it has to do with a <a href="https://en.wikipedia.org/wiki/XS_(Perl)">foreign function interface</a> for perl. In other words,
the issue is not really with the specific module at all. It is rather some kind
of problem with module loading in general. Replacing <code>use DateTime;</code> with e.g.
<code>use Moose;</code> results in an identical error message.</p>
<h2>Summary</h2>
<p>What is to learn? Not much which wasn't already known. Installing software
should ideally be done using system tools. Using tools like <em>cpanm</em>, <em>cargo</em>,
<em>gem</em>, <em>luarocks</em>, <em>pipx</em>, et cetera such should ideally be avoided. Yet as we
know, one really can't. So the only real take away for my part is that an eight
year old bug, originally reported against 5.24.0, recently got a patch accepted
and will likely be in a future release of Perl. Maybe in 5.42.0? I've stopped
myself short of trying to understand Perl's <a href="https://metacpan.org/dist/perl/view/Porting/release_schedule.pod">release schedule</a>. Fingers
crossed, it lands before the release of OpenBSD 7.8.</p>
]]></description><guid>https://blog.netizen.se/p/unspecific-perl-error/</guid><pubDate>Sun, 04 May 2025 20:00:48 +0000</pubDate></item><item><title>Using a MacBookPro11,1</title><link>https://blog.netizen.se/p/using-a-macbookpro11,1/</link><description><![CDATA[<h2>Background</h2>
<p>About a year ago I was given a <a href="https://support.apple.com/en-us/108052">MacBookPro11,1</a> (A1502 EMC 2678). This is a mid-2014 model. Its original owner considered it no longer useful to him, as Apple supposedly has dropped support for it in all current macOS releases.</p>
<p>For the first year I ended up using it with FreeBSD while concurrently running alpine linux in a bhyve, because that is how pragmatic problem solving works. This setup broke for me when upgrading to FreeBSD-14.2p3. Or rather, I didn't redo the few required additional steps. I figured the better path surely must be to fully switch to linux. So switched I did.</p>
<p>These are my thoughts from this experience. Please consider most of the text to describe an art project with limitied practical utility. A beautiful thing which will unfortunately never materialize.</p>
<h2>Options</h2>
<p>While there are literally hundreds of operating systems for intel machines in general, the remaining options drastically reduce when targetting specifically Apple hardware. Many might say macOS, which these computers come with, would be the natural choice. Yet I'm quite sure it is not for me. Apple software is far too opinionated for my taste. Not to mention failing at non-functional aspects such as respecting user privacy and what not. Maybe some versions of Microsoft Windows would run on the machine. I have not investigated that, since it practically becomes uninteresting for the same reasons as macOS. Windows might arguably even be worse than macOS.</p>
<p>With the most limiting factor being wifi, the only remaining kernels to consider are <a href="https://en.wikipedia.org/wiki/XNU">XNU</a> and Linux. That might be a confusing statement, given that macOS was just ruled out as an option for me — Here are rabbit holes to dive down into. What one needs to initially understand is that the contract between Apple and Broadcom appears to have been that the latter license their wifi solution to the former and "take full responsability" from a business perspective. While I don't have actual insight in this, I would say it is fair to assume that only Broadcom has ever had legal access to the wifi driver source code. Neither Apple nor anyone else are likely to ever have had it. Broadcom have compiled and released drivers to platforms of their choice. Contractual obligations and other business reasons has of course influenced their selected platforms to cover the majority of the market. Still, unless one downloads a binary for one of their selected platforms, their wifi interfaces are fully useless.</p>
<p>Drivers for some interfaces have been reverse engineered and I might be sloppy in expressing where the boundaries of firmware and drivers are. Possibly also being technically incorrect about other details, but the main point here is that the laptop model I received fully lacks networking without Broadcom's driver blob.</p>
<h2>FreeBSD</h2>
<p>As mentioned above in the background section, I did run FreeBSD for about a year. With <a href="https://man.freebsd.org/wifibox">wifibox(8)</a> providing an alpine based router in a bhyve. Installation is as simple as merely installing the wifibox packages from ports. That setup apparently the only way to the any networking under FreeBSD with these Broadcom BCM4360 (14e4:43a0) equipped laptops. Even though it required running Linux in a virtual machine, wifi actually worked quite well. So did most other things I tried. The internal speakers stayed silent, but sound did work when having headphones connected. As I have a separate dedicated laptop for video conferencing, I never did try the camera nor any other stuff I never needed. The thing which I noticed to not work was suspend/resume. When rebuilding the kernel without SMP I could get to a state where the machine actually woke up, but it was acting all weird after doing so. This lead to me having the laptop turned on for weeks, awake while I was asleep myself. It naturally also limitied the practical portability of the machine. Laptops just are better when suspend and resume are working than when not.</p>
<h2>Darwin</h2>
<p>Being mostly new to the Apple ecosystem, I assumed it ought to be possible to run some <a href="https://en.wikipedia.org/wiki/Darwin_(operating_system)">Darwin distribution</a> on this machine. That is however a very faulty assumption. Just to make sure all readers are on track, <a href="https://en.wikipedia.org/wiki/XNU">XNU</a> is the kernel used in <a href="https://en.wikipedia.org/wiki/Darwin_(operating_system)">Darwin</a>. A detailed understanding can be found by reading the Wikipedia pages linked in the previous sentence, but in summary: OpenDarwin was shut down in 2006 and PureDarwin about a decade later. To the best of my understanding, the only currently alive Darwin derivatives are macOS and its siblings which  Apple maintains for their other product lines.</p>
<p>In theory one could probably revive an open source Darwin distribution. It would be a lot of work. Way too much work to be realistic for me to engage in it. But since the "correct" kernel for this hardware is XNU, and that kernel should ideally deserve a life outside of macOS, its a fun thought experiment to entertain for a bit. As none of the open Darwin distributions ever included drivers for the closed broadcom wifi adapters, one may assume that was a huge factor in why the projects failed. When Apple hardware effectively was lacking network, macOS naturally became the only viable option.</p>
<p>If one were to build Darwin this year, to use it on an old macbook, would it be technically feasible to somehow yank the wifi drivers from a macOS installation and shoehorn them into a working state for that system? Unlikely, is my answer. Sure — in the sense that anything is possible, it should be doable. It wouldn't be fun though. Legally sketchy too. Not fun at all!</p>
<p>Something which seems like a more fun path to take appears when realizing there is a derivative of bhyve called <a href="https://github.com/machyve/xhyve">xhyve</a>. What if one could mimic the environment I ran for a year, but replacing FreeBSD with a Darwin. Wouldn't that be fun? Resurrecting Open/Pure-Darwin into its third incarnation seems like a suggestion to bring forward. Timely now with it being easter and all. Unfortunately that idea quickly falls flat due to:</p>
<blockquote>
<p>xhyve is equivalent to the bhyve process but gains a subset of a userspace port of the vmm kernel module. SVM, <strong>PCI passthrough</strong> and the VMX host and EPT aspects are/[<strong>is] dropped</strong>.</p>
</blockquote>
<p>Having PCI passthrough is of course absolutely essential. The requirement to implement that would be a bridge too far, to put it mildly. Especially considering how bringing back Darwin would need a huge amount of work, and that running xhyve on that rather than macOS probably already would be quite a project in itself.</p>
<h2>macOS</h2>
<p>While actually running macOS as it is intended is out of the question, one idea would be to boot it with a heavily modified configuration. With so intrusive changes that it would be unrecognizable as macOS, even if it would technically still be it. I'm imagining taking it to a state where it essentially only hosts a hypervisor running something more sensible operating system. It is a mad idea, which I will not pursuit. A quick search turned up these links on how to <a href="https://bill.welliver.org/space/start/2017-05/running_macos_x_without_a_gui">run macOS without a gui</a> or <a href="https://apple.stackexchange.com/q/119027/login-directly-to-terminal">reenable <code>&gt;console</code> login</a>, which seem to say that one actually could be able to disable everything unwanted on macOS and use it like a real unix system. Apple doesn't make it easy though. As is apparent from the content reachable by following those links, one might say Apple are even actively making it increasingly harder to turn their consumer devices into actual computers.</p>
<h2>alpine linux</h2>
<p>In the end I went with installing alpine linux, for at least two reasons. It is a nice distribution, and it is what I have experienced already working for this wifi hardware inside of bhyve. Getting working wifi turned out to still be a bit of a journey, which will likely be part of an upcoming text soon. Suspend and resume worked pretty much out of the box though!</p>
]]></description><guid>https://blog.netizen.se/p/using-a-macbookpro11,1/</guid><pubDate>Sun, 20 Apr 2025 20:02:25 +0000</pubDate></item><item><title>Deserting Debian</title><link>https://blog.netizen.se/p/deserting-debian/</link><description><![CDATA[<p>As mentioned in my last post, on <a href="/p/daily-operating-system-rotation/">daily operating system rotation</a>, I'm
kind of giving up on using Debian. It is not entirely clear whether this really
warrants its own blog post or not, but here it is.</p>
<p>Decades ago I found myself running Debian on most of my systems, and I was
happy doing that. While I never did become a debian developer, some might claim
I was still fairly deeply invested. I did package software, both my own and
other's, and distributed some of it through my personal apt repositories. Had I
blogged about it back when it happened, it would probably have been interesting
to tell what once drew me to Debian. But that ship has sailed, and this post
will instead cover what made me aband ship.</p>
<p>You know how sometimes people attempt to solve problems you're not even having?</p>
<p>Back in my youth we had something called <a href="https://en.wikipedia.org/wiki/Open_Sound_System">OSS</a>. I can't remember all the
details, but I did actually pay money for a license once. It still sucked. Only
one process at the time could open the sound device. Thus there was an ongoing
struggle to hunt and kill that process in order to instead allow the desired
one to play sounds. Then came <a href="https://en.wikipedia.org/wiki/Advanced_Linux_Sound_Architecture">ALSA</a> and all Linux related sound problems
were gone. At least for a while, until suddenly someone did that thing of
attempting to solve some fully unexperienced problem, and brought us back to a
world resembling the one of OSS. However with the difference that the audio was
always stolen by the same culprit. The hunt could be eliminated. We learnt that
if we ran <code>sudo killall -9 pulseaudio</code> whenever the computer had gone silent,
we got audio working again. Annoying, but only mildly so. It eventually got
better. I guess some heroes fixed something.</p>
<p>A few years later history repeated itself. I'm not naming names, and try to not
place blame on the doers. One can however not avoid noticing that quality of
Debian has seriously suffered since the project decided to fix a problem many
people were not at all having. Don't get me wrong. I do understand the
challenges of sysvinit, and even was the supervisor for a couple of master
thesis students looking at bringing in <a href="https://en.wikipedia.org/wiki/Upstart_(software)">upstart</a> into the products of my
employer back in those days. Still, I wish Debian could have had chosen a path
with less random breakage. Too much has already been written about how the pid
1 replacement could had been done better. I have nothing construtive to add,
and no illusions that I'll ever feel at home again. I have attempted to run
<a href="https://en.wikipedia.org/wiki/Devuan">Devuan</a> here and there, but understand it to be an underresourced
project with a close to impossible mission.</p>
<p>To be clear, I don't envision a future without ever touching a Debian, or even
an Ubuntu, system. However the time when those would had been among my first
choice are likely gone forever.</p>
<p>These ramblings might not have added much value, but I still felt it
appropriate to post. Apologies to any readers feeling their time being
wasted.</p>
]]></description><guid>https://blog.netizen.se/p/deserting-debian/</guid><pubDate>Sun, 10 Nov 2024 22:00:31 +0000</pubDate></item><item><title>Daily operating system rotation</title><link>https://blog.netizen.se/p/daily-operating-system-rotation/</link><description><![CDATA[<p>Sometimes one gets drawn to really bad ideas. Thoughts may occur, which one
know are so silly that the best action would be to forget all about them and
move on to instead do something better. Still these bad ideas have something
too compelling to them, making it impossible to not feel like pursuing them.
I've acted on one such thing now. This is the blog post about it.</p>
<p>Lets start with some background. A few years back I found myself to be stuck in
a monoculture. Monocultures as such are typically always a bad thing. Still
this was one which I had actively chosen, and once upon a time decided to go
all in on. Yet the world tends to change around you, and suddenly you might
find what was previously your favorite spot to later be an undesired place.
The monoculture in question was <a href="https://en.wikipedia.org/wiki/Debian">Debian Linux</a>. An operating system I
then ran on all my computers. Servers, laptops, embedded stuff, everything. For
a couple of decades I practically used nothing else. At least not where I could
make that choice. It's ironic how I could end up with essentially all eggs in
one operating system basket, given my previous experience with and love for
more diverse environments.</p>
<div class="simplistic">
<p><a href="../img/laptopstack.jpeg"><img src="../img/laptopstack_320x320.png" alt="laptopstack" /></a></p>
</div>
<p>Now what's written in the previous paragraph is not 100% factual, but it feels
true. During the period described I have e.g. been doing software development
on both OpenWRT and illumos based systems for customers, and I installed and
ran <a href="https://en.wikipedia.org/wiki/bitrig">bitrig</a> on a personal laptop for quite a while when that was a thing. I
have transitioned into using FreeBSD on both my primary laptop and on servers
during the last couple of years. That feels a lot better than Debian. Still, am
I perhaps just replacing one monoculture with another? Realizing that I have,
not all with working batteries but in total, about seven laptops of varying age
I am now trying an insane experiment. Once a day I am switching which operating
system to use.</p>
<p>Unless I have tasks that require to be done one a certain system, I attempt to
every morning pick the laptop installed with that weekday's operating system.
Thus my goal is to run <a href="https://en.wikipedia.org/wiki/FreeBSD">FreeBSD</a> on Mondays, <a href="https://en.wikipedia.org/wiki/Alpine_Linux">Alpine Linux</a> on
Tuesdays, <a href="https://en.wikipedia.org/wiki/OpenIndiana">OpenIndiana</a> on Wednesdays, <a href="https://en.wikipedia.org/wiki/OpenBSD">OpenBSD</a> on Thursdays,
<a href="https://en.wikipedia.org/wiki/Darwin_(operating_system)">Darwin</a> on Fridays and <a href="https://en.wikipedia.org/wiki/Haiku_(operating_system)">Haiku</a> on Sundays.  Saturdays are left
open for playing around with toy operating systems, or more mature ones, in
virtual machines. My aim is to do this for something three to six months or so.
Maybe slightly shorter, maybe longer, but definitely not perpetually. I'm not
sure exactly what happens after that. I am hoping to learn how to use computers
in a more abstract manner, reducing my tendency to unnecessarily make use of too
implementation specific details. My expection is to land in perhaps becoming
better in selecting platforms suitable for their task. Though any kind of
valuable insights are welcome.</p>
<p>Some people who know me might have been shocked to read about my choice for
Fridays. Darwin practically means macOS, and that will without doubt be the
most challenging part of this experiment. Apple are quite keen on taking away
control from users. I am annoyed with that experience already, but hope I will
learn something and come out stronger.</p>
]]></description><guid>https://blog.netizen.se/p/daily-operating-system-rotation/</guid><pubDate>Sun, 27 Oct 2024 20:44:24 +0000</pubDate></item><item><title>Captcha, the Microsoft GitHub way</title><link>https://blog.netizen.se/p/captcha,-the-microsoft-github-way/</link><description><![CDATA[<p>Naturally, I've had accounts with Microsoft GitHub (MSGH) in the past. I treat
accounts for that platform like one should, closing them whenever done with the
task or project requiring one. I then go on with my life, using proper working
tools for those Git repositories anyone actually cares about in a loving way.
Leaving, of course, nothing but the well-known <a href="https://github.com/ghost">ghost</a> as the keeper of my
history on those neglected enough to be under the 🤮-platform.</p>
<p>Not too long ago I encountered the need for an account again, tried to sign-up
and was then given twenty top-view pictures of furnished rooms. I was also
asked to select which one would match, from a list of similar looking pictures.
I failed.</p>
<p>Could you, dear readers, please help me spot the correct ones?</p>
<p><em>Find the room that matches the middle image (16 of 20)</em></p>
<div class="centered">
<p><img src="../img/msgh-captcha16.png" alt="msgh16" /></p>
</div>
<p><em>Find the room that matches the middle image (19 of 20)</em></p>
<div class="centered">
<p><img src="../img/msgh-captcha19.png" alt="msgh19" /></p>
</div>
<p>Obviously those two captchas are unsolvable, as both room images match the
aerial view. Others have suggested that this might be intentional behaviour, in
order to filter out unwanted users. I hold it as more probable that it is simply
just a bug. Regardless of which, it makes any attempt to sign-up very time
consuming at best and definitely not worth it unless you're desperate to be on
a team which does not want you.</p>
<p>Some people might ask: Why would you go through the trouble of closing and
opening new accounts rather than keeping a life-long one? A question to which
my first reaction would be amazement over the trust people have in that evil
entities will never become their enemies.</p>
<p>Rather than leaving the illusion that one would be able to perpetually reach me
within a walled garden, I prefer doing the responsible thing and remain only
reachable through my communicated and preferred contact channels. Personally, I
have always managed to close my accounts before being booted out. Yet you know,
either you close your GitHub account yourself, or it is done for you.  This
platform is all about algorithm driven moderation, with no due process nor ways
to appeal. Trust me, in truly technical circles you won't need to ask long
before encountering someone who had their account taken away from them for no
reason other than a detection of "suspicious activity". Not to say that I
actually belong to any truly technical circles myself.</p>
<p>In addition to what I have written above, I'm not exactly a fan of how MSGH
actually functions. Compared to other Git workflows, the platform is horrible
to use. It hides easy operations behind an extremely unfriendly web user
interface. One might argue that it is also possible to navigate using their
custom API, and that might be true. Still, even if one were to setup an
ergonomic workflow through scripting and custom tooling, there would still be
issues. Most annoyingly the fact that, unless you publish a spam-trap email or
are lucky enough to have the repository owner adding custom configuration, MSGH
forcefully rewrites author headers to junk. Above that, it's beyond me how
anyone can be happy with a Git change integration system where it is
practically impossible to stack branches in a merge queue.</p>
<p>Dear software maintainers using MSGH, I urge you to please avoid forcing your
choice upon others. Clearly merging from another remote must be easier for
everyone involved than to do the dance of pointless pull-requests when no
discussion is required. In case there are workflows guarding code quality,
please make it easy to run those test-suites locally, prior to pushing.
Everyone benefits from less administration and more value addition.</p>
]]></description><guid>https://blog.netizen.se/p/captcha,-the-microsoft-github-way/</guid><pubDate>Sun, 07 Jul 2024 19:17:36 +0000</pubDate></item><item><title>Vim syntax plugin: preseed</title><link>https://blog.netizen.se/p/vim-syntax-plugin-preseed/</link><description><![CDATA[<p>Given that this blog contains a few posts about preseeding debian installation,
it should not come as a surprise to recurring readers that I occasionally edit
preseed files. Please see <a href="https://en.wikipedia.org/wiki/Preseed">Wikipedia</a> for an introduction to the general
topic.</p>
<p>An annoyance when editing these files in <a href="https://en.wikipedia.org/wiki/Vim_(text_editor)">vim</a>, my editor of choice, has
been the lack of syntax highlighting. During the last few days, I read up on
the topic, wrote the plugin <a href="https://git.netizen.se/vim-preseed">vim-preseed</a> and published it to <a href="https://www.vim.org/scripts/script.php?script_id=6087">vim.org</a>
for anyone to download and use. With that plugin installed, anyone can enjoy
editing their preseed files with some assistance to conveniently get visual
feedback on errors such as missing a backslash at the end of a line or
accidentally using a <code>string</code> instead of a <code>select</code>.</p>
<p>Unfortunately the preseed code-blocks in posts on this blog still lack syntax
highlighting, but I guess the natural workaround now is to copy and paste them
into vim and view them there!</p>
]]></description><guid>https://blog.netizen.se/p/vim-syntax-plugin-preseed/</guid><pubDate>Sun, 15 Oct 2023 16:42:17 +0000</pubDate></item><item><title>Rust Crate: libsyslog</title><link>https://blog.netizen.se/p/rust-crate-libsyslog/</link><description><![CDATA[<p>A couple of months ago I released two Rust crates, my first public ones ever.
They are published on crates.io as <a href="https://crates.io/crates/libsyslog">libsyslog</a> and <a href="https://crates.io/crates/libsyslog-sys">libsyslog-sys</a>. During
the past week I held a presentation about them at <a href="https://cph.rs/">our local Rust
group</a>'s 36:th meetup. No recording was made, but the slide deck is
available via the thumbnail below.</p>
<div class="simplistic">
<p><a href="../pdf/cph_rs-libsyslog.pdf"><img src="../img/cph_rs-libsyslog.png" alt="show slides" title="Open slides" /></a></p>
</div>
<p>Those slides differ slightly from the version actually shown during the event.
Some slides have had aesthetic changes, but the slides are also updated after
correcting a major bug. As it turns out, one of the best ways of getting a
proper code review is to stand in front of a somewhat large group of people,
inviting them to spot your mistakes.</p>
<p>In case blogging also invites similar sharp eyes, it might be appropriate to
point out that I do realize the libsyslog-sys crate could probably be
considered redundant with the <a href="https://crates.io/crates/libc">libc</a> crate already exposing the same API. An
upcoming release is highly likely to retire it.</p>
]]></description><guid>https://blog.netizen.se/p/rust-crate-libsyslog/</guid><pubDate>Sun, 28 May 2023 21:54:14 +0000</pubDate></item><item><title>Multiple Irc Clients Multiplexed Over Tmux</title><link>https://blog.netizen.se/p/multiple-irc-clients-multiplexed-over-tmux/</link><description><![CDATA[<p>There are very many ways to send instant messages and participate in group
chats. I'm one of those who <a href="https://xkcd.com/1782/">xkcd #1782</a> is about, who prefers <a href="https://en.wikipedia.org/wiki/IRC">IRC</a>
over anything else.</p>
<p>With many people using other networks and platforms, it is desirable to in one
way or another make those technologies accessible from an irc client. For years
I've been having setups enabling sms text messaging with an irc like interface,
and there are some vague memories of me being an early enough adoptor of
<a href="https://www.bitlbee.org/">bitlbee</a> to have provided hosting for its web pages in the early days.</p>
<p>A couple of months ago I moved to using my regular irc client for Slack and
Matrix, which made for a great increase in usability. However it also resulted
in there being too many channels and too little segmentation. Weechat has
a feature request in <a href="https://github.com/weechat/weechat/issues/741">issue #471</a> with title <em>Support multiple hotlists</em>
which could address this problem, but zero progress has been made since the
ticket was filed six years ago. Properly designing and implementing that change
is a too large project for me to be bothered with. Instead I hacked up
<a href="https://git.netizen.se/micmot/">micmot</a>, an ugly workaround which kind of accomplishes the same thing.</p>
<p>Multiple Irc Clients Multiplexed Over Tmux (micmot) is a couple scripts for
irssi, weechat and the shell to abuse <a href="https://en.wikipedia.org/wiki/Tmux">tmux</a> to give an overview over chat
activity in multiple irc clients.</p>
<pre style="background-color:#2b303b;">
<span style="color:#c0c5ce;"></span>
<span style="color:#c0c5ce;">                                 _                      __</span>
<span style="color:#c0c5ce;">                      ____ ___  (_)________ ___  ____  / /_</span>
<span style="color:#c0c5ce;">                     / __ `__ \/ / ___/ __ `__ \/ __ \/ __/</span>
<span style="color:#c0c5ce;">                    / / / / / / / /__/ / / / / / /_/ / /_</span>
<span style="color:#c0c5ce;">                   /_/ /_/ /_/_/\___/_/ /_/ /_/\____/\__/</span>
<span style="color:#c0c5ce;"></span>
<span style="color:#c0c5ce;">  d Launch weechat for slack as user slack</span>
<span style="color:#c0c5ce;">  i Launch irssi as current user</span>
<span style="color:#c0c5ce;">  w Launch weechat as current user</span>
<span style="color:#c0c5ce;"></span>
<span style="color:#c0c5ce;">  q Quit micmot. (Will not kill other panes)</span>
<span style="color:#c0c5ce;"></span>
<span style="color:#c0c5ce;">></span>
<span style="color:#c0c5ce;"></span>
<span style="background-color: green; foreground-color: black;">[chat] 0:micmot* 1:weechat- 2:[#channel,someone]- 3:slack >"micmot" 23:54 02-Oct-22</span>
</pre>
<p>As can be seen above, the name for pane number 2 in the status line has been
changed from <em>irssi</em> to <em>[#channel,someone]</em>, indicating that there are unread
messages on the channel <em>#channel</em> and from the person <em>someone</em> in the irssi
client. Had there been new messages in the weechat client on pane 1, or the
weechat instance named <em>slack</em> on pane 3, those panes would had been renamed
too. Visiting a pane resets the name back to the default.</p>
<p>Anyone actually interested in using this is encouraged to clone the
<a href="https://git.netizen.se/micmot/">repository</a>, read the source code and configure irssi/weechat to load
the script(s). Please let me know if finding it useful.</p>
]]></description><guid>https://blog.netizen.se/p/multiple-irc-clients-multiplexed-over-tmux/</guid><pubDate>Sun, 02 Oct 2022 21:58:35 +0000</pubDate></item><item><title>Command-line Currency Conversion</title><link>https://blog.netizen.se/p/command-line-currency-conversion/</link><description><![CDATA[<p>In my opinion, the <a href="https://en.wikipedia.org/wiki/Terminal_emulator">terminal</a> is almost always the most desired interface for
using any computer, and I prefer to stay in that friendly environment for as
long as possible. It is a pleasant place to be, predictable and fairly free
from unwanted distractions. Any task I can get done from the terminal, I want
to perform there. To be clear I especially am not a fan of unnecessarily
needing to open a browser to the contemporary world wide web, having to spend
minutes on rejecting cookies, dismissing pop-ups and pointy-clickying barely
navigatable pages in order to find facts which should merely take seconds to
find. One type of information provoking such a struggle is currency conversion
rates. I do infrequently, but recurringly, need to look those up.</p>
<p>Searching for how others was solving this I found this <a href="https://old.reddit.com/r/commandline/comments/hl6524/commandline_currency_converter/">reddit thread</a>
which essentially gave nothing. I also found the tools <a href="https://github.com/juanpagfe/cash">cash</a>, <a href="https://github.com/emsikei/ccov">ccov</a>,
<a href="https://github.com/NARKOZ/mmc">mmc</a>, <a href="https://lib.rs/crates/rates">rates</a>, <a href="https://lib.rs/crates/sesters">sesters</a> and a bunch of others all claiming to be
intended for currency conversion, but with the common limitation that they all
only handle exchange rates for the point in time at which they are run.
While a pragmatic soul might claim fluctuations even out over time, that's
never the perspective held by accountants or tax clerks. Insignificant details
such as getting every transaction locked to the exact right day is what they
love to enforce, and I do actually understand why they do cause all the
annoyance. With it typically being a couple of days between me having an
expense and spending the happy fun time to file an expense report or add it to
my accounting, the tools above do not meet my need.</p>
<p>For a while I feared I would have to hack up my own little tool. I found this
introductionary text on <a href="http://www.yacoset.com/how-to-handle-currency-conversions">How to handle money and currency conversions</a>
by Chris Wenham, and then I realized that <a href="https://lib.rs/crates/rusty-money">rusty-money</a> seemed to be written
in accordancy to that text. In essence; use quantified decimal representation
rather than fractional floats and always defer conversions as long as possible.
That's possibly also true for <a href="https://code.google.com/archive/p/python-money/">python-money</a> (<a href="https://pypi.org/project/python-money/">pypi</a>)
which hasn't been updated for over a decade.</p>
<p>I learned that there are a close to infinite amount of entities providing API:s
for currency conversion, but they all require registering for an API key and
forming a relationship. Which is way too high maintenance for what I was
looking for. The <a href="https://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html">European Central Bank</a> publishes a dataset with daily
exchange rates, and that tends to be what sane people actually use. It appears
the <a href="https://www.riksbank.se/sv/statistik/sok-rantor--valutakurser/">Swedish Central Bank</a> (<a href="https://www.riksbank.se/sv/statistik/sok-rantor--valutakurser/oppet-api/">SOAP API</a>) provides data
too, but short of actually investigating it, I suspect it might just be the
ECB's data repackaged.</p>
<p>While looking at possibly implementing the tool in python rather than Rust, I
realized that this <a href="http://alexprengere.github.io/currencyconverter/">currencyconverter</a> (<a href="https://pypi.org/project/CurrencyConverter/">pypi</a>)
library actually contains a command line utility meeting all my needs. As this
does not seem to be packaged by Debian, one must do something like <code>pip3 install --user currencyconverter</code> to install it. Once that is done a call like
the following reveals the cost a train ride I had to do for work a couple of
days ago:</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#c0c5ce;">% currency_converter</span><span style="color:#bf616a;"> --to</span><span style="color:#c0c5ce;"> SEK</span><span style="color:#bf616a;"> --date</span><span style="color:#c0c5ce;"> 2022-09-16 210 DKK
</span><span style="color:#8fa1b3;">210.000</span><span style="color:#c0c5ce;"> DKK = 303.682 SEK on 2022-09-16
</span></code></pre>
<p>Beware that (in version 0.17.1) there is no error detected when converting for
a missing date, so make sure to keep the conversion database updated. A
convenient way to accomplish that without having to think about it is to add
this function to <code>.zshrc</code>:</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#8fa1b3;">currency_converter</span><span style="color:#c0c5ce;">() {
</span><span style="color:#c0c5ce;">  </span><span style="color:#b48ead;">local </span><span style="color:#bf616a;">python_version</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">( </span><span style="color:#8fa1b3;">python3</span><span style="color:#bf616a;"> --version </span><span style="color:#a3be8c;">)</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">  </span><span style="color:#bf616a;">python_version</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">python_version</span><span style="color:#c0c5ce;">#* </span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">  </span><span style="color:#b48ead;">local </span><span style="color:#bf616a;">max_age</span><span style="color:#c0c5ce;">=</span><span style="color:#a3be8c;">1 </span><span style="color:#65737e;"># Days of age before refreshing the file.
</span><span style="color:#c0c5ce;">  </span><span style="color:#b48ead;">local </span><span style="color:#bf616a;">eurofxref_url _eurofxref_file state
</span><span style="color:#c0c5ce;">  </span><span style="color:#bf616a;">eurofxref_url</span><span style="color:#c0c5ce;">=&#39;</span><span style="color:#a3be8c;">https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.zip</span><span style="color:#c0c5ce;">&#39;
</span><span style="color:#c0c5ce;">  </span><span style="color:#bf616a;">eurofxref_file</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">( </span><span style="color:#96b5b4;">printf </span><span style="color:#c0c5ce;">&quot;</span><span style="color:#a3be8c;">%s/%spython%s%s%s</span><span style="color:#c0c5ce;">&quot; &quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">HOME</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; &quot;</span><span style="color:#a3be8c;">.local/lib/</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#a3be8c;">\
</span><span style="color:#a3be8c;">      </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">python_version</span><span style="color:#c0c5ce;">%</span><span style="color:#a3be8c;">.</span><span style="color:#c0c5ce;">*</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; &quot;</span><span style="color:#a3be8c;">/site-packages/currency_converter/</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#a3be8c;">\
</span><span style="color:#a3be8c;">      </span><span style="color:#c0c5ce;">&quot;</span><span style="color:#a3be8c;">eurofxref-hist.zip</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#a3be8c;">)</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">  </span><span style="color:#bf616a;">state</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">( </span><span style="color:#8fa1b3;">find </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">eurofxref_file</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;</span><span style="color:#bf616a;"> -mtime </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">max_age</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;</span><span style="color:#bf616a;"> -printf </span><span style="color:#c0c5ce;">&#39;</span><span style="color:#a3be8c;">OK</span><span style="color:#c0c5ce;">&#39; || </span><span style="color:#8fa1b3;">:</span><span style="color:#a3be8c;">)</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">  </span><span style="color:#b48ead;">if </span><span style="color:#96b5b4;">[ </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">state</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; != &#39;</span><span style="color:#a3be8c;">OK</span><span style="color:#c0c5ce;">&#39; </span><span style="color:#96b5b4;">]</span><span style="color:#c0c5ce;">; </span><span style="color:#b48ead;">then
</span><span style="color:#c0c5ce;">    </span><span style="color:#8fa1b3;">wget</span><span style="color:#bf616a;"> --output-document </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">eurofxref_file</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; &quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">eurofxref_url</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">  </span><span style="color:#b48ead;">fi
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">  </span><span style="color:#96b5b4;">command</span><span style="color:#c0c5ce;"> currency_converter &quot;$</span><span style="color:#bf616a;">@</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">}
</span></code></pre>
<p>That wraps all calls to <code>currency_converter</code>, performing an up-to-date check
and automatic database download prior to calling the actual command.</p>
]]></description><guid>https://blog.netizen.se/p/command-line-currency-conversion/</guid><pubDate>Sun, 18 Sep 2022 06:02:21 +0000</pubDate></item><item><title>Practical Pushing of Rebased Chains</title><link>https://blog.netizen.se/p/practical-pushing-of-rebased-chains/</link><description><![CDATA[<p>The previous post, <a href="../practical-rebasing-of-chained-branches/">Practical Rebasing of Chained Branches</a>, covered how to
use a custom git command to rebase several git branches stacked on each other.
Once wishing to share a set of branches; pushing a chain to a server risks
becoming another tedious task. Unless using something like this custom git
command, which I call <code>git-force-push-chain</code></p>
]]></description><guid>https://blog.netizen.se/p/practical-pushing-of-rebased-chains/</guid><pubDate>Sun, 04 Sep 2022 09:18:18 +0000</pubDate></item><item><title>Practical Rebasing of Chained Branches</title><link>https://blog.netizen.se/p/practical-rebasing-of-chained-branches/</link><description><![CDATA[<p>As most readers of this blog post would be well aware of, <a href="https://en.wikipedia.org/wiki/Git">git</a> is a tool
used essentially daily by all software developers. I would wish to claim that
we lived in a world where everyone also used its <code>rebase</code> command to make sure
their commit history is understandable and easy to follow, but that is
unfortunately not always the case. I would urge anyone who is not yet
proficient with using git rebase in <a href="https://git-scm.com/docs/git-rebase#_interactive_mode">interactive</a> mode, to please consider to
spending a moment to learn it properly. To gain any value from what follows, it
is likely a prerequisite to have a clear understanding of why one wants to
spend effort on cleaning-up messy work prior to submitting it. Junior
developers might want to read something like Anna Shipman's blog post <a href="https://www.annashipman.co.uk/jfdi/good-pull-requests.html">How to
raise a good pull request</a> first.</p>
<p>While git is great at making interactive rebases of single branches, it quickly
gets out of hand when working with multiple branches stacked or chained
together. Say for example that we have a situation like the one in the left
image below. With <code>topic/some_branch</code>, <code>topic/other_branch</code> and
<code>topic/yet_another_branch</code> being actively worked upon and unfinished, while
<code>main</code> has moved since work started on this stack of branches. Our goal is to
gain a repository like the one in the image on the right, where all work
branches have been rebased upon <code>main</code>.</p>
<div class="centered">
<p><img src="../img/branch-chain-behind.png" alt="branches behind" />
<img src="../img/branch-chain-rebased.png" alt="branches rebased" /></p>
</div>
<p>One would of course wish to merge everything early, never needing to end up
with having to rebase entire trains of branches. Yet, reality has a tendency to
mess with ideal models. That which can not be avoided, needs to instead be
handled. Some searching seemed to suggest that people tend to either roll
their own scripts or adapt super-heavy workflows to solve this problem. After
having attempted to reuse someone else's unmaintained and broken script, I
decided to do like everyone else and reinvent the wheel.</p>
<p>Meet <code>git-rb</code>, a script which aids in rebasing related branches by creatively
wrapping the editor, by setting the <code>GIT_SEQUENCE_EDITOR</code> environment variable
to pre-populate the sequence with labels affected by the rebase:</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#65737e;">#!/bin/sh -eu
</span><span style="color:#c0c5ce;">
</span><span style="color:#65737e;"># Version 2.18 (commit 9055e4) of git added the required &#39;label&#39; functionality.
</span><span style="color:#bf616a;">_min_major_version</span><span style="color:#c0c5ce;">=</span><span style="color:#a3be8c;">2
</span><span style="color:#bf616a;">_min_minor_version</span><span style="color:#c0c5ce;">=</span><span style="color:#a3be8c;">18
</span><span style="color:#c0c5ce;">
</span><span style="color:#bf616a;">_git_version</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">( </span><span style="color:#8fa1b3;">git</span><span style="color:#a3be8c;"> version )</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#bf616a;">_git_major_version</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_git_version</span><span style="color:#c0c5ce;">##* </span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#bf616a;">_git_minor_version</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_git_version</span><span style="color:#c0c5ce;">#*</span><span style="color:#a3be8c;">.}</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#bf616a;">_git_major_version</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_git_major_version</span><span style="color:#c0c5ce;">%%</span><span style="color:#a3be8c;">.</span><span style="color:#c0c5ce;">*</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#bf616a;">_git_minor_version</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_git_minor_version</span><span style="color:#c0c5ce;">%%</span><span style="color:#a3be8c;">.</span><span style="color:#c0c5ce;">*</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">
</span><span style="color:#96b5b4;">unset</span><span style="color:#c0c5ce;"> _git_version
</span><span style="color:#c0c5ce;">
</span><span style="color:#b48ead;">if </span><span style="color:#96b5b4;">[ </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_git_major_version</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#bf616a;">-lt </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_min_major_version</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#96b5b4;">] </span><span style="color:#c0c5ce;">||
</span><span style="color:#c0c5ce;">    </span><span style="color:#96b5b4;">[ </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_git_major_version</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; = &quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_min_major_version</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#96b5b4;">] </span><span style="color:#c0c5ce;">&amp;&amp;
</span><span style="color:#c0c5ce;">    </span><span style="color:#96b5b4;">[ </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_git_minor_version</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#bf616a;">-lt </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_min_minor_version</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#96b5b4;">]</span><span style="color:#c0c5ce;">;
</span><span style="color:#b48ead;">then
</span><span style="color:#c0c5ce;">  </span><span style="color:#96b5b4;">echo </span><span style="color:#c0c5ce;">&quot;</span><span style="color:#a3be8c;">Git </span><span style="color:#c0c5ce;">$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_git_major_version</span><span style="color:#a3be8c;">}.</span><span style="color:#c0c5ce;">$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_git_minor_version</span><span style="color:#a3be8c;">} detected.</span><span style="color:#c0c5ce;">&quot; \
</span><span style="color:#c0c5ce;">     &quot;</span><span style="color:#a3be8c;">Minimum </span><span style="color:#c0c5ce;">$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_min_major_version</span><span style="color:#a3be8c;">}.</span><span style="color:#c0c5ce;">$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_min_minor_version</span><span style="color:#a3be8c;">} required.</span><span style="color:#c0c5ce;">&quot; &gt;&amp;</span><span style="color:#d08770;">2
</span><span style="color:#c0c5ce;">  </span><span style="color:#96b5b4;">exit</span><span style="color:#c0c5ce;"> 1
</span><span style="color:#b48ead;">fi
</span><span style="color:#c0c5ce;">
</span><span style="color:#96b5b4;">unset</span><span style="color:#c0c5ce;"> _git_major_version _git_minor_version \
</span><span style="color:#c0c5ce;">    _min_major_version _min_minor_version
</span><span style="color:#c0c5ce;">
</span><span style="color:#bf616a;">_script_dir</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">( </span><span style="color:#8fa1b3;">dirname </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">0</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#a3be8c;">)</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#bf616a;">GIT_SEQUENCE_EDITOR</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_script_dir</span><span style="color:#a3be8c;">}/branch-moving-wrapper</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#8fa1b3;">git</span><span style="color:#c0c5ce;"> rebase &quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">@</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">
</span><span style="color:#96b5b4;">unset</span><span style="color:#c0c5ce;"> _script_dir
</span></code></pre>
<p>That other script, <code>branch-moving-wrapper</code>, does the heavy lifting. It suggests
to move every chained branch together with the rebase, and it looks like:</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#65737e;">#!/bin/sh -eu
</span><span style="color:#c0c5ce;">
</span><span style="color:#bf616a;">_head</span><span style="color:#c0c5ce;">=$</span><span style="color:#a3be8c;">( </span><span style="color:#8fa1b3;">git</span><span style="color:#a3be8c;"> rev-parse</span><span style="color:#bf616a;"> --short</span><span style="color:#a3be8c;"> HEAD )
</span><span style="color:#c0c5ce;">
</span><span style="color:#b48ead;">if </span><span style="color:#c0c5ce;">! </span><span style="color:#8fa1b3;">grep</span><span style="color:#bf616a;"> -q </span><span style="color:#c0c5ce;">&#39;</span><span style="color:#a3be8c;">^exec git branch</span><span style="color:#c0c5ce;">&#39; &quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">1</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;; </span><span style="color:#b48ead;">then
</span><span style="color:#c0c5ce;">  </span><span style="color:#b48ead;">for</span><span style="color:#c0c5ce;"> _hash </span><span style="color:#b48ead;">in</span><span style="color:#c0c5ce;"> IFS=&quot; &quot; $( </span><span style="color:#8fa1b3;">awk </span><span style="color:#c0c5ce;">&lt; &quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">1</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; &#39;</span><span style="color:#a3be8c;">$1==&quot;pick&quot; { print $2 }</span><span style="color:#c0c5ce;">&#39; ); </span><span style="color:#b48ead;">do
</span><span style="color:#c0c5ce;">    </span><span style="color:#96b5b4;">[ </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_hash</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; != &quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_head</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#96b5b4;">] </span><span style="color:#c0c5ce;">|| </span><span style="color:#b48ead;">continue
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">    </span><span style="color:#b48ead;">for</span><span style="color:#c0c5ce;"> _branch </span><span style="color:#b48ead;">in </span><span style="color:#c0c5ce;">$( </span><span style="color:#8fa1b3;">git</span><span style="color:#c0c5ce;"> branch</span><span style="color:#bf616a;"> --points-at </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_hash</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; | </span><span style="color:#8fa1b3;">cut</span><span style="color:#bf616a;"> -c3- </span><span style="color:#c0c5ce;">); </span><span style="color:#b48ead;">do
</span><span style="color:#c0c5ce;">      </span><span style="color:#bf616a;">_sequence</span><span style="color:#c0c5ce;">=&quot;$</span><span style="color:#a3be8c;">( </span><span style="color:#8fa1b3;">awk </span><span style="color:#c0c5ce;">&lt;&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">1</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; </span><span style="color:#96b5b4;">\ </span><span style="color:#c0c5ce;">&#39;</span><span style="color:#a3be8c;">{
</span><span style="color:#a3be8c;">          if ($0 ~ /^pick </span><span style="color:#c0c5ce;">&#39;&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_hash</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;&#39;</span><span style="color:#a3be8c;">/) {
</span><span style="color:#a3be8c;">            print; print &quot;label </span><span style="color:#c0c5ce;">&#39;&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_branch</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;&#39;</span><span style="color:#a3be8c;">&quot;
</span><span style="color:#a3be8c;">          } else {
</span><span style="color:#a3be8c;">            print
</span><span style="color:#a3be8c;">          }
</span><span style="color:#a3be8c;">        }</span><span style="color:#c0c5ce;">&#39; | </span><span style="color:#8fa1b3;">awk </span><span style="color:#c0c5ce;">&#39;</span><span style="color:#a3be8c;">{
</span><span style="color:#a3be8c;">          if ($0 ~ /^# Rebase /) {
</span><span style="color:#a3be8c;">            print &quot;exec &quot; \
</span><span style="color:#a3be8c;">                &quot;git branch --force </span><span style="color:#c0c5ce;">&#39;&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_branch</span><span style="color:#a3be8c;">} refs/rewritten/</span><span style="color:#c0c5ce;">$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_branch</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;&#39;</span><span style="color:#a3be8c;">&quot;;
</span><span style="color:#a3be8c;">            print
</span><span style="color:#a3be8c;">          } else {
</span><span style="color:#a3be8c;">            print
</span><span style="color:#a3be8c;">          }
</span><span style="color:#a3be8c;">        }</span><span style="color:#c0c5ce;">&#39;
</span><span style="color:#a3be8c;">      )</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">      </span><span style="color:#96b5b4;">echo </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">_sequence</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot; &gt;&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">1</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">    </span><span style="color:#b48ead;">done
</span><span style="color:#c0c5ce;">  </span><span style="color:#b48ead;">done
</span><span style="color:#b48ead;">fi
</span><span style="color:#c0c5ce;">
</span><span style="color:#96b5b4;">unset</span><span style="color:#c0c5ce;"> _branch _hash _head _sequence
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">$</span><span style="color:#8fa1b3;">{</span><span style="color:#bf616a;">VISUAL</span><span style="color:#c0c5ce;">:-</span><span style="color:#8fa1b3;">vi} </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">@</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;
</span></code></pre>
<p>Given that the scripts gets placed in some directory in PATH, one should be
able to use <code>git rb --interactive main</code> to have dependant branches move
together with the rebase of the leaf branch. Please see the images below for a
rebase resulting in a transition between the example from the images above. The
lines starting with <code>label</code> and <code>exec</code> are the interesting ones added by the
script.</p>
<div class="simplistic">
<p><img src="../img/branch-chain-cli.png" alt="cli" /></p>
</div>
<p>Beware, the above relies on replacing the editor with a script injecting
commands into the sequence list and wrapping the editor. It lacks error
checking for a bunch of possible scenarios. Only use it if you understand how
it works.</p>
<p>By placing the following in <code>~/.zshrc</code>, <a href="https://zsh.org/">zsh</a> can be made to inherit tab
completion of options and arguments from <code>git-rebase</code>.</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#8fa1b3;">_git-rb</span><span style="color:#c0c5ce;">() {
</span><span style="color:#c0c5ce;">  </span><span style="color:#8fa1b3;">_git-rebase </span><span style="color:#c0c5ce;">&quot;$</span><span style="color:#a3be8c;">{</span><span style="color:#bf616a;">@</span><span style="color:#a3be8c;">}</span><span style="color:#c0c5ce;">&quot;
</span><span style="color:#c0c5ce;">}
</span><span style="color:#c0c5ce;">
</span><span style="color:#8fa1b3;">compdef</span><span style="color:#c0c5ce;"> _git-rb git-rb
</span></code></pre>
]]></description><guid>https://blog.netizen.se/p/practical-rebasing-of-chained-branches/</guid><pubDate>Sun, 21 Aug 2022 19:25:36 +0000</pubDate></item><item><title>Partial zsh Config</title><link>https://blog.netizen.se/p/partial-zsh-config/</link><description><![CDATA[<p>Here follows some of my zsh configuration, as promised in my <a href="../a-zshrc-skeleton/">previous
post</a>. Please see that previous post for understanding where
to place these and how they are used.</p>
<p>First out is <code>zshenv.illumos</code> which gets conditionally included on illumos
(solaris) hosts. It does nothing more than adding a few directories to the
start of the list of directories searched for executables, given that those
paths exist.</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;"># vim: filetype=zsh sw=2 et
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;"># /opt/onbld/bin/i386 /opt/ooce/docbook-xsl/tools /usr/xpg4/bin /usr/share/lib
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">for _path in \
</span><span style="color:#c0c5ce;">    &#39;/usr/gnu/bin&#39; \
</span><span style="color:#c0c5ce;">    &#39;/usr/ccs/bin&#39; \
</span><span style="color:#c0c5ce;">    &#39;/opt/ooce/bin&#39;
</span><span style="color:#c0c5ce;">do
</span><span style="color:#c0c5ce;">  if [ &quot;${PATH//${_path}/}&quot; = &quot;${PATH}&quot; ] &amp;&amp; [ -e &quot;${_path}&quot; ]; then
</span><span style="color:#c0c5ce;">    PATH=&quot;${_path}:${PATH}&quot;
</span><span style="color:#c0c5ce;">  fi
</span><span style="color:#c0c5ce;">done
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">unset _path
</span><span style="color:#c0c5ce;">export PATH
</span><span style="color:#c0c5ce;">
</span></code></pre>
<p>The second file here <code>zshenv.cloud</code> creates a few convenience functions for
easily finding cloud computing instances. The stack exchange links in the
comments are pretty much where I have copy'n'pasted the oneliners from, and
they are mostly used by my secure shell configuration.</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#c0c5ce;"># vim: filetype=zsh sw=2 et
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;"># https://stackoverflow.com/q/25922609/#50535409
</span><span style="color:#c0c5ce;">#   does-google-publish-a-dns-record-for-google-compute-engine-instances
</span><span style="color:#c0c5ce;">get_gce_ip() {
</span><span style="color:#c0c5ce;">  local instance=&quot;${1%%.*}&quot;
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">  gcloud compute instances list --filter=&quot;$instance&quot; \
</span><span style="color:#c0c5ce;">      --format=&#39;value(networkInterfaces[0].accessConfigs[0].natIP)&#39;
</span><span style="color:#c0c5ce;">}
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;"># https://serverfault.com/q/734237/
</span><span style="color:#c0c5ce;">#   is-there-a-command-to-list-aws-instances-that-results-in-short-output
</span><span style="color:#c0c5ce;">get_aws_fqdn() {
</span><span style="color:#c0c5ce;">  local instance=&quot;${1%%.*}&quot;
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">  aws ec2 describe-instances --filters &quot;Name=tag:Name,Values=${instance}&quot; \
</span><span style="color:#c0c5ce;">      --output text --query &#39;Reservations[*].Instances[*].[PublicDnsName]&#39;
</span><span style="color:#c0c5ce;">}
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">get_linode_ip() {
</span><span style="color:#c0c5ce;">  local instance=&quot;${1%%.*}&quot;
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">  linode-cli --json linodes list --label &quot;${instance}&quot; |
</span><span style="color:#c0c5ce;">      jq --raw-output &#39;.[0].ipv4[0]&#39;
</span><span style="color:#c0c5ce;">}
</span></code></pre>
<p>In order to make your linodes, ec2:s and gce:s conveniently available under
some fake top level domains, just add the corresponding <code>cloud.conf</code> somewhere
and include it from <code>.ssh/config</code>:</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#c0c5ce;"># vim: ft=sshconfig sw=4
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">Host *.aws
</span><span style="color:#c0c5ce;">    ProxyCommand nc $( get_aws_fqdn &quot;%h&quot; ) %p
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;"># https://stackoverflow.com/q/25922609/#50535409-dns-record-for-gce-instance
</span><span style="color:#c0c5ce;">Host *.googl
</span><span style="color:#c0c5ce;">    ProxyCommand nc $( get_gce_ip &quot;%h&quot; ) %p
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">Host *.linode
</span><span style="color:#c0c5ce;">    ProxyCommand nc $( get_linode_ip &quot;%h&quot; ) %p
</span></code></pre>
<p>The third and last zsh config file in this post is <code>zshrc.prompt</code> which is only
used for interactive shells. The <a href="https://zsh.sourceforge.io/Doc/Release/Prompt-Expansion.html">manual</a> does a better job than I could do
at describing how the percent preceeded characters are expanded. One might
maybe start out reading it with the understanding that a ternary operator style
expression is used to make the prompt red when the previous command failed.</p>
<pre style="background-color:#2b303b;">
<code><span style="color:#c0c5ce;"># vim: filetype=zsh sw=2 et
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">PROMPT=&quot;%(?..%S%F{red})%D{%Y%m%d}|%T|%!|%m%#&quot;
</span><span style="color:#c0c5ce;">RPROMPT=&quot;%(?..%S%F{red})&quot;
</span><span style="color:#c0c5ce;">
</span><span style="color:#c0c5ce;">PROMPT+=&quot;%f%s &quot;
</span><span style="color:#c0c5ce;">export PROMPT RPROMPT
</span></code></pre>
<p>Clearly these are not my full set of zsh configuration files, but a bite sized
chunk. Maybe there will be more in the future, maybe not. To some degree that
depends on whether these first two zsh posts are well recieved by those who
initially requested the topic.</p>
]]></description><guid>https://blog.netizen.se/p/partial-zsh-config/</guid><pubDate>Sun, 07 Aug 2022 08:28:36 +0000</pubDate></item><item><title>A .zshrc Skeleton</title><link>https://blog.netizen.se/p/a-zshrc-skeleton/</link><description><![CDATA[<p><a href="https://en.wikipedia.org/wiki/Z_shell">Z-shell</a> has been my command line interpreter of choice for decades.
Someone recently asked me whether I could provide a copy of my <code>.zshrc</code>, the
startup initialization file configuring how the shell should respond to its
controlling user. As these files tend to become a bit personal, they are not
easily shared in their entirety. Posting my unedited file(s) would likely not
be useful to any audience. No two individuals have the exact same preferences
or needs. If that would had been the case, the configuration files would not
have needed to exist in the first place.</p>
]]></description><guid>https://blog.netizen.se/p/a-zshrc-skeleton/</guid><pubDate>Sun, 24 Jul 2022 13:56:48 +0000</pubDate></item><item><title>Event Invites through SourceHut</title><link>https://blog.netizen.se/p/event-invites-through-sourcehut/</link><description><![CDATA[<p><b>Note: It turns out the premise this post was based on is incorrect. It turns
out that, although poorly documented, SourceHut does have a reasonable
configuration of default allowed mime types.</b></p>
]]></description><guid>https://blog.netizen.se/p/event-invites-through-sourcehut/</guid><pubDate>Sun, 10 Jul 2022 19:46:00 +0000</pubDate></item><item><title>Seasonal Outdoors Laptop</title><link>https://blog.netizen.se/p/seasonal-outdoors-laptop/</link><description><![CDATA[<p>Summer is upon us and the weather is for once absolutely wonderful, with
sunshine and temperatures occasionally reaching 30°C. While I'm not fully on
top of the latest developments on screen technology, I do know that it is a
challenge to read anything on any of my laptops if attempting to use them
outdoors during this time of the year.</p>
]]></description><guid>https://blog.netizen.se/p/seasonal-outdoors-laptop/</guid><pubDate>Sun, 26 Jun 2022 17:53:54 +0000</pubDate></item><item><title>Named Locations on a Garmin Watch</title><link>https://blog.netizen.se/p/named-locations-on-a-garmin-watch/</link><description><![CDATA[<p>As has been mentioned more than once on this blog; <a href="/p/going-wrist-watch/">I wear a Garmin
watch</a> and I keep it out of the clouds, relying only on open software to
transfer data to and from it.</p>
]]></description><guid>https://blog.netizen.se/p/named-locations-on-a-garmin-watch/</guid><pubDate>Sun, 12 Jun 2022 20:18:32 +0000</pubDate></item><item><title>Posting a Question to Stack Exchange</title><link>https://blog.netizen.se/p/posting-a-question-to-stack_exchange/</link><description><![CDATA[<p>Let us first establish that we all know about <a href="https://en.wikipedia.org/wiki/Stack_Exchange">Stack Exchange</a> — the
questions and answers network where a huge part of the human combined knowledge
is both available and expandable.</p>
]]></description><guid>https://blog.netizen.se/p/posting-a-question-to-stack_exchange/</guid><pubDate>Sun, 29 May 2022 16:15:11 +0000</pubDate></item><item><title>The face of my Garmin watch</title><link>https://blog.netizen.se/p/the-face-of-my-garmin-watch/</link><description><![CDATA[<p>Followers of this blog know that I am <a href="/p/going-wrist-watch/">a Garmin watch wearer</a>, and that
I have mentioned things to think about when <a href="/p/hints-for-when-installing-garmin-connectiq/">installing ConnectIQ</a>.</p>
]]></description><guid>https://blog.netizen.se/p/the-face-of-my-garmin-watch/</guid><pubDate>Sun, 15 May 2022 10:58:31 +0000</pubDate></item><item><title>Filing Swedish taxes in 2022</title><link>https://blog.netizen.se/p/filing-swedish-taxes-in-2022/</link><description><![CDATA[<p>It is tax season. One could think that filing taxes would be possible to do
online in the year of 2022, but in Sweden the most practical way to do it is
still by filling in paper forms, and queuing in line to hand them in at the tax
office.</p>
]]></description><guid>https://blog.netizen.se/p/filing-swedish-taxes-in-2022/</guid><pubDate>Sun, 01 May 2022 15:35:51 +0000</pubDate></item><item><title>Hints for when installing Garmin ConnectIQ SDK</title><link>https://blog.netizen.se/p/hints-for-when-installing-garmin-connectiq/</link><description><![CDATA[<p>Disclosure: It's been quite some delay between writing this text and actually
posting it. A year and a half or so. Given that I could have written an
identical post yet a year prior to that, when installing the SDK my first time,
I simply assume these are perpetually true and still relevant facts.</p>
]]></description><guid>https://blog.netizen.se/p/hints-for-when-installing-garmin-connectiq/</guid><pubDate>Sun, 17 Apr 2022 07:14:10 +0000</pubDate></item><item><title>Using AGM M7 with a Dark Background</title><link>https://blog.netizen.se/p/using-agm-m7-with-a-dark-background/</link><description><![CDATA[<p>My <a href="../buying-a-phone-in-2021/">previous post</a> mentions how I got myself an AGM
M7. A simplistic phone deserves a neat background.  However due to some bug in
the firmware, it unfortunately does not seem possible use the phone after to
setting the background to fully black. Attempting to do so will result in the
user interface switching to white text on white background. Please let me know
if you understand how avoid that.</p>
]]></description><guid>https://blog.netizen.se/p/using-agm-m7-with-a-dark-background/</guid><pubDate>Sun, 05 Dec 2021 22:20:10 +0000</pubDate></item><item><title>Buying a Phone in 2021</title><link>https://blog.netizen.se/p/buying-a-phone-in-2021/</link><description><![CDATA[<p>Sadly, my <a href="https://jolla-devices.com/intex-aqua-fish/">Intex Aqua Fish</a> has seen better days. While I've lived with
minor hardware issues such as the broken on/off-button, a no longer working
camera and that discolored blob on the left of the screen for a couple of
years, the need to replace the device came from the USB port loosening to the
level where charging the battery now is a real challenge. These years with
<a href="https://en.wikipedia.org/wiki/Sailfish_OS">Sailfish OS</a> have been a blessing. However unlike four to five years ago,
it is no longer possible to buy a device with it pre-installed. Since buying a
supposedly supported device, fiddling with flashing a new firmware to it and
all which comes with that, felt like the opposite of appealing, I reluctantly
decided to look for other alternatives.</p>
]]></description><guid>https://blog.netizen.se/p/buying-a-phone-in-2021/</guid><pubDate>Sun, 21 Nov 2021 17:36:03 +0000</pubDate></item><item><title>A Minor Postrunner Contribution</title><link>https://blog.netizen.se/p/a-minor-postrunner-contribution/</link><description><![CDATA[<p><a href="../using-ruby-software-with-local-patches/">The previous post</a> covered how to handle locally patched Ruby software. I'm
glad to write that <a href="https://git.netizen.se/postrunner/commit/?id=4d9649fee9bb8c8cf5ca18c2aa9c96283c229574">my patch</a> was already merged at the time of publishing,
and that <a href="https://github.com/scrapper/postrunner/compare/v1.0.2...v1.0.4">it is included</a> in postrunner v1.0.4 released during the past
week.</p>
]]></description><guid>https://blog.netizen.se/p/a-minor-postrunner-contribution/</guid><pubDate>Sun, 21 Feb 2021 00:21:00 +0100</pubDate></item><item><title>Using Ruby Software with Local Patches</title><link>https://blog.netizen.se/p/using-ruby-software-with-local-patches/</link><description><![CDATA[<p>Unfortunately I don't really know <a href="https://www.ruby-lang.org/">Ruby</a>, nor do
expect I will anytime soon. Yet there is software written in that language
which I use, and occasionally want to make (trivial) adaptions to.</p>
]]></description><guid>https://blog.netizen.se/p/using-ruby-software-with-local-patches/</guid><pubDate>Sun, 20 Sep 2020 21:06:24 +0000</pubDate></item><item><title>Going Wrist Watch</title><link>https://blog.netizen.se/p/going-wrist-watch/</link><description><![CDATA[<p>For the clear majority of my life, I've keep my wrist naked of any ubiquitous time
telling device and have been very happy with that sense of freedom. A couple of
years ago however, I surprised myself and bought a watch. There were a couple
of reasons for doing so, but the main one was to improve my exercising. For a
year or two prior to that purchase, I went through the hassle of wearing a
pulse strap and a small android device (without a sim-card) whenever I went
running.</p>
]]></description><guid>https://blog.netizen.se/p/going-wrist-watch/</guid><pubDate>Sun, 02 Aug 2020 19:56:40 +0000</pubDate></item><item><title>Using RunnerUpLive in 2020</title><link>https://blog.netizen.se/p/using-runneruplive-in-2020/</link><description><![CDATA[<p>Yesterday a friend of mine ran a race, which reminded me of the patching I did
right before running my first and only organized half-marathon a couple of
years ago.</p>
]]></description><guid>https://blog.netizen.se/p/using-runneruplive-in-2020/</guid><pubDate>Sun, 19 Jul 2020 21:59:41 +0000</pubDate></item><item><title>Laptop passwords. Typing once, using twice</title><link>https://blog.netizen.se/p/laptop-passwords-typing-once,-using-twice/</link><description><![CDATA[<p>In case anyone studied <a href="../hiding-debian-s-complex-partitioning/">my previous blog post</a> very carefully, it was
possible to get a hint on today's topic. The <code>lvm-simple-parametric.sh</code> script
referenced there, contains lines attempting to use a passphrase which will only
be available after doing something similar to what follows below.</p>
]]></description><guid>https://blog.netizen.se/p/laptop-passwords-typing-once,-using-twice/</guid><pubDate>Sun, 14 Jun 2020 18:17:11 +0000</pubDate></item><item><title>Hiding Debian&apos;s complex partitioning</title><link>https://blog.netizen.se/p/hiding-debian-s-complex-partitioning/</link><description><![CDATA[<p>Just like the last few posts on this blog, this post is about utilizing Debian
installer using preseed configuration. Please consider reading the previous
posts, starting at the one on <a href="../multiple-custom-commands-with-debian-installer/">scripting flexibility</a>.</p>
]]></description><guid>https://blog.netizen.se/p/hiding-debian-s-complex-partitioning/</guid><pubDate>Sun, 31 May 2020 17:06:22 +0000</pubDate></item><item><title>Fetch and run with Debian Installer</title><link>https://blog.netizen.se/p/fetch-and-run-with-debian-installer/</link><description><![CDATA[<p>A few weeks ago, there was <a href="../multiple-custom-commands-with-debian-installer/">a post on this blog</a> introducing
<code>scripting_flexibility.txt</code>. In order to understand what follows, please read
that post first.</p>
]]></description><guid>https://blog.netizen.se/p/fetch-and-run-with-debian-installer/</guid><pubDate>Sun, 17 May 2020 21:01:32 +0000</pubDate></item><item><title>Preserving SSH host keys when re-installing Debian</title><link>https://blog.netizen.se/p/preserving-ssh-host-keys-when-reinstalling-debian/</link><description><![CDATA[<p>This post attempts to describe a practical take on how to simplify the task of
keeping old <a href="https://man.openbsd.org/ssh#VERIFYING_HOST_KEYS">OpenSSH host keys</a> when reinstalling servers running the Debian
operating system or any of its derivatives such as e.g. Ubuntu. This might, or
might not, be a good idea depending on circumstances. My previous blog post
<a href="/p/multiple-custom-commands-with-debian-installer/">multiple custom commands with Debian Installer</a> is recommended reading.</p>
]]></description><guid>https://blog.netizen.se/p/preserving-ssh-host-keys-when-reinstalling-debian/</guid><pubDate>Sun, 03 May 2020 21:54:37 +0000</pubDate></item><item><title>Restrict sudo to keys</title><link>https://blog.netizen.se/p/restrict-sudo-to-ssh-keys/</link><description><![CDATA[<p>As was described in the <a href="../multiple-custom-commands-with-debian-installer/">previous blog post</a>, one can easily
increase the flexibility of debian preseeding. It might be worth visiting that
post before reading this one, to have the context.</p>
]]></description><guid>https://blog.netizen.se/p/restrict-sudo-to-ssh-keys/</guid><pubDate>Sun, 19 Apr 2020 13:40:35 +0000</pubDate></item><item><title>Multiple custom commands with Debian Installer</title><link>https://blog.netizen.se/p/multiple-custom-commands-with-debian-installer/</link><description><![CDATA[<p>When installing Debian, or any derivative such as e.g. Ubuntu on a computer, it
is possible to use templates to automate the installation. Such templates are
called preseed files and are explained in the <a href="https://www.debian.org/releases/buster/amd64/apb.en.html">Installation Guide</a>.</p>
]]></description><guid>https://blog.netizen.se/p/multiple-custom-commands-with-debian-installer/</guid><pubDate>Sun, 05 Apr 2020 18:05:50 +0000</pubDate></item><item><title>Calling Rust code on Android</title><link>https://blog.netizen.se/p/rust-on-android/</link><description><![CDATA[<p>Roughly a year ago I held a small presentation at our local Rust group's hacknight on the topic of calling a Rust function from inside an android java application. At the time I had no appropriate place to host the slides, but now there is this blog. So better late than never, you can find my slides published below.</p>
]]></description><guid>https://blog.netizen.se/p/rust-on-android/</guid><pubDate>Sun, 22 Mar 2020 17:57:18 +0000</pubDate></item></channel></rss>
