<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>The Voidcruiser</title>
    <link>/</link>
    <description>Recent content in Home on The Voidcruiser</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 10 Aug 2022 14:19:40 +0200</lastBuildDate><atom:link href="/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Distortions</title>
      <link>/rambles/distortions/</link>
      <pubDate>Thu, 26 Sep 2024 17:14:09 +0200</pubDate>
      
      <guid>/rambles/distortions/</guid>
      <description>&lt;h1 id=&#34;festering-ideas&#34;&gt;Festering Ideas&lt;/h1&gt;
&lt;p&gt;&lt;details&gt;
	&lt;summary&gt;
		Epilepsy warning
	&lt;/summary&gt;


&lt;figure &gt;&lt;img src=&#34;/images/distortions/butchered.gif&#34; alt=&#34;A gif with flickering text saying &amp;#39;butchered&amp;#39;&#34;&gt;&lt;/figure&gt;

&lt;/details&gt;
&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve always liked glitchy looking images and videos. I just never bothered
creating my own. That is until I came across the
&lt;a href=&#34;https://dyne.org/software/frei0r/&#34;&gt;&lt;code&gt;frei0r&lt;/code&gt;&lt;/a&gt; library by the
&lt;a href=&#34;https://dyne.org&#34;&gt;Dyne&lt;/a&gt; project. Here I found the &lt;code&gt;glitch0r&lt;/code&gt; effect and messed
around with it for a bit in Kdenlive. However, as a terminal terminal user,
using a graphical interface didn&amp;rsquo;t feel right. So I figured out how to use the
&lt;code&gt;frei0r&lt;/code&gt; effects with &lt;code&gt;ffmpeg&lt;/code&gt;.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; Now I could script the butchering of a bunch of
files at once!&lt;/p&gt;
&lt;p&gt;Among the effects in &lt;code&gt;frei0r&lt;/code&gt;, I also found &lt;code&gt;scanline0r&lt;/code&gt; and a bunch of other
effect, but wasn&amp;rsquo;t quite happy with the fact that the scanlines in question seem
to be stuck at one resolution. Some time later (a few years), I heard someone
complain about professional footage being interlaced and it looking like shit as
a result. Upon closer inspection it had been the kind of ugly mess I&amp;rsquo;d been
hoping to create with the &lt;code&gt;scanline0r&lt;/code&gt; filter. So I got around to figure out how
to interlace video using &lt;code&gt;ffmpeg&lt;/code&gt; and butchered some videos further.&lt;/p&gt;
&lt;h2 id=&#34;first-manifestations&#34;&gt;First Manifestations&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a demonstration of what I managed to do so far using Big Buck Bunny as an
example:&lt;/p&gt;


&lt;figure &gt;
	&lt;video width=&#34;500&#34;controls&gt;
		&lt;source src=&#34;/videos/distortions/rabbit_original.mp4&#34; type=&#34;video/mp4&#34; controls &gt;
	&lt;/video&gt;&lt;figcaption&gt;
		&lt;i&gt;Original clip from Big Buck Bunny&lt;/i&gt;
	&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;This snippet was chopped up using &lt;code&gt;ffmpeg&lt;/code&gt; using the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ffmpeg -ss 00:01:17 -i big_buck_bunny_720p_h264.mov -to 00:00:11.75 rabbit_original.mp4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;details&gt;
	&lt;summary&gt;
		Epilepsy warning
	&lt;/summary&gt;



&lt;figure &gt;
	&lt;video width=&#34;500&#34;controls&gt;
		&lt;source src=&#34;/videos/distortions/rabbit_mangled.mp4&#34; type=&#34;video/mp4&#34; controls &gt;
	&lt;/video&gt;&lt;figcaption&gt;
		&lt;i&gt;My butchered version&lt;/i&gt;
	&lt;/figcaption&gt;&lt;/figure&gt;

&lt;/details&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ffmpeg -ss 00:01:17 -i big_buck_bunny_720p_h264.mov -vf &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#39;frei0r=filter_name=glitch0r:filter_params=0.05|0.8|.02|1,rgbashift=rh=6:bh=-4,interlace=scan=tff:lowpass=complex,format=yuva420p&amp;#39;&lt;/span&gt; -to 00:00:11.75 rabbit_mangled.mp4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The full original video can be found on &lt;a href=&#34;https://peach.blender.org/&#34;&gt;the Big Buck Bunny website&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;magick&#34;&gt;Magick&lt;/h1&gt;
&lt;p&gt;In the mean time, I had been messing around with imagemagick as well. Using it
to create pictures of words of phrases when I felt like it. Usually I would use
something like the following to that end:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;magick -font &lt;span style=&#34;color:#fe8019&#34;&gt;$(&lt;/span&gt;magick -list font | grep Font: | awk &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt; | fzf&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt; -pointsize &lt;span style=&#34;color:#d3869b&#34;&gt;288&lt;/span&gt; -fill white -stroke black -strokewidth &lt;span style=&#34;color:#d3869b&#34;&gt;5&lt;/span&gt; -background transparent label:&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;*Insert text here*&amp;#34;&lt;/span&gt; example.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure &gt;&lt;img src=&#34;/images/distortions/example.png&#34; alt=&#34;Here I used the Iosevka font to create an image with the text *Insert text here*&#34;&gt;&lt;figcaption&gt;
		&lt;i&gt;The font used is Iosevka&lt;/i&gt;
	&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h1 id=&#34;black-magick&#34;&gt;Black Magick&lt;/h1&gt;
&lt;p&gt;So the other day, I thought it would be interesting to see if I could make some
text using imagemagick and then feed it to &lt;code&gt;ffmpeg&lt;/code&gt; to create a gif with an
interesting glitch effect.&lt;/p&gt;
&lt;h3 id=&#34;initial-text&#34;&gt;Initial text&lt;/h3&gt;
&lt;p&gt;Some text made with imagemagick because its the easiest way I know to create a
simple image with text.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;magick -font Iosevka -pointsize &lt;span style=&#34;color:#d3869b&#34;&gt;300&lt;/span&gt; -fill cyan -background transparent label:&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;Glitch&amp;#34;&lt;/span&gt; glitch.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure &gt;&lt;img src=&#34;/images/distortions/glitch.png&#34; alt=&#34;An image with cyan text saying &amp;#39;Glitch&amp;#39;&#34;&gt;&lt;/figure&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: The &lt;code&gt;pointsize&lt;/code&gt; here is relevant as &lt;code&gt;ffmpeg&lt;/code&gt; will complain if the image
has a pixel count not divisible by 2. 300 works with Iosevka, if it doesn&amp;rsquo;t
work with your font of choice, try a few sizes until you find one that does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;with-glitch0r&#34;&gt;With glitch0r&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ffmpeg -loop &lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt; -i glitch.png -vf &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#39;frei0r=filter_name=glitch0r:filter_params=0.05|0.8|.02|1&amp;#39;&lt;/span&gt; -t &lt;span style=&#34;color:#d3869b&#34;&gt;10&lt;/span&gt; glitch.gif
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure &gt;&lt;img src=&#34;/images/distortions/glitch.gif&#34; alt=&#34;The same image as above but with generated/artificial interference using the glitch0r effect from the frei0r library&#34;&gt;&lt;/figure&gt;

&lt;h3 id=&#34;mangled-results-with-imagemagick&#34;&gt;Mangled results with imagemagick&lt;/h3&gt;
&lt;p&gt;Initial results looked quite interesting. Then I thought it&amp;rsquo;d be funny to
convert this gif to an apng &amp;ndash; animated png. This resulted in the gif being
butchered in a really interesting way due to something in imagemagick being
broken; when converting the gif to an apng using &lt;code&gt;ffmpeg&lt;/code&gt;, it will come out on
the other end in a state you&amp;rsquo;d expect.&lt;/p&gt;
&lt;p&gt;&lt;details&gt;
	&lt;summary&gt;
		Epilepsy warning
	&lt;/summary&gt;


&lt;figure &gt;&lt;img src=&#34;/images/distortions/glitch_butchered.gif&#34; alt=&#34;A variant of the same image as before, but horrible broken due to the aforementioned bug in imagemagick&#34;&gt;&lt;/figure&gt;

&lt;/details&gt;
&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;magick glitch.gif APNG:glitch_animated.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: You have to supply the fileformat in prefix form as apng isn&amp;rsquo;t the
standard format for the &amp;lsquo;png&amp;rsquo; file extension.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After creating the apng I decided to convert it back to a gif in order to save
some space as the apng was 11M.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;magick APNG:glitch_animated.png glitch_butchered.gif
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I experimented a bit with both &lt;code&gt;ffmpeg&lt;/code&gt; and imagemagick to see what the best
results would be. &lt;code&gt;ffmpeg&lt;/code&gt; is significantly faster with the default settings but
has a slightly large filesize.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ls -lh glitch_*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-rw------- &lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt; yog-sothoth users  11M Sep &lt;span style=&#34;color:#d3869b&#34;&gt;26&lt;/span&gt; 18:57 glitch_animated.png
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-rw-r--r-- &lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt; yog-sothoth users 5,1M Sep &lt;span style=&#34;color:#d3869b&#34;&gt;27&lt;/span&gt; 09:48 glitch_ffmpeg.gif
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-rw-r--r-- &lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt; yog-sothoth users 4,2M Sep &lt;span style=&#34;color:#d3869b&#34;&gt;27&lt;/span&gt; 09:49 glitch_magick.gif
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: No, I have no idea why the apng has a umask of &lt;code&gt;077&lt;/code&gt;. Imagemagick just
spat it out like that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I hadn&amp;rsquo;t seen anyone butcher visuals quite like this before, so I thought I&amp;rsquo;d
write a post about it with the idea that someone else might find it interesting.&lt;/p&gt;
&lt;p&gt;So, go out there and butcher some visuals!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;For many of the frei0r effects I used Kdenlive to figure out their parameters.
And for a list of available filters, I checked the &lt;code&gt;ffmpeg-filters(1)&lt;/code&gt; manpage and
looked for &lt;code&gt;frei0r&lt;/code&gt;. Under the &lt;code&gt;filter_name&lt;/code&gt; section, there are a few paths
listed where ffmpeg checks for &lt;code&gt;frei0r&lt;/code&gt; filters.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Config Snippets</title>
      <link>/rambles/config-snippets/</link>
      <pubDate>Tue, 09 Apr 2024 18:38:46 +0200</pubDate>
      
      <guid>/rambles/config-snippets/</guid>
      <description>&lt;h1 id=&#34;mess&#34;&gt;Mess&lt;/h1&gt;
&lt;p&gt;First I&amp;rsquo;m going to address an elephant in the room:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why aren&amp;rsquo;t you publishing your dotfiles?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They&amp;rsquo;re too much of a mess with a bunch personal data entwined in the commit
history that I don&amp;rsquo;t feel comfortable publicly throwing onto the internet.&lt;/p&gt;
&lt;h1 id=&#34;nix-snippets&#34;&gt;Nix snippets&lt;/h1&gt;
&lt;p&gt;It&amp;rsquo;s no secret that I&amp;rsquo;ve picked up NixOS a few years ago. To that end, there are
a few things that I don&amp;rsquo;t think I&amp;rsquo;ve seen other people do that I would like to
share here.&lt;/p&gt;
&lt;h2 id=&#34;home-manager-color-scheme&#34;&gt;&lt;code&gt;home-manager&lt;/code&gt; color scheme&lt;/h2&gt;
&lt;p&gt;Some time ago, I came across the
&lt;a href=&#34;https://github.com/Misterio77/nix-colors&#34;&gt;nix-colors&lt;/a&gt; project and came to the
conclusion that it didn&amp;rsquo;t fit my needs. As a result, I put/hacked a function
together that extracts the color schemes from
&lt;a href=&#34;https://search.nixos.org/packages?show=kitty-themes&amp;amp;query=kitty-themes&#34;&gt;&lt;code&gt;pkgs.kitty-themes&lt;/code&gt;&lt;/a&gt;.
I won&amp;rsquo;t go into the integration details in my personal config as it&amp;rsquo;s not
exactly something I would call ergonomic. However, this is the function I came
up with:&lt;/p&gt;
&lt;details&gt;
	&lt;summary&gt;
		Expand to see a rather lengthy nix expression
	&lt;/summary&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ lib&lt;span style=&#34;color:#fe8019&#34;&gt;,&lt;/span&gt; config&lt;span style=&#34;color:#fe8019&#34;&gt;,&lt;/span&gt; pkgs&lt;span style=&#34;color:#fe8019&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt; }:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;arg:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;with&lt;/span&gt; lib;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;let&lt;/span&gt; cfg &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; config&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;colorscheme;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    getKittyTheme &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;builtins&lt;/span&gt;; (theme:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#fe8019&#34;&gt;let&lt;/span&gt; matching &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; filter (x: x&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;name &lt;span style=&#34;color:#fe8019&#34;&gt;==&lt;/span&gt; theme)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (fromJSON
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (readFile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;${&lt;/span&gt;pkgs&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;kitty-themes&lt;span style=&#34;color:#b8bb26&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;/share/kitty-themes/themes.json&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#fe8019&#34;&gt;in&lt;/span&gt; throwIf (length matching &lt;span style=&#34;color:#fe8019&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;kitty-themes does not contain a theme named &lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;${&lt;/span&gt;theme&lt;span style=&#34;color:#b8bb26&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;${&lt;/span&gt;pkgs&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;kitty-themes&lt;span style=&#34;color:#b8bb26&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;/share/kitty-themes/&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;${&lt;/span&gt;(head matching)&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;file&lt;span style=&#34;color:#b8bb26&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    unwrapKittyTheme &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;with&lt;/span&gt; pkgs; path: &lt;span style=&#34;color:#fe8019&#34;&gt;let&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      theme &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; runCommand &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;theme.toml&amp;#34;&lt;/span&gt; { nativebuildinputs &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; [ coreutils ]; } &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;          cat &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;${&lt;/span&gt;path&lt;span style=&#34;color:#b8bb26&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#39; | sed -E &amp;#39;/^#|^$/d;s/\s+(.*)/ = &amp;#34;\1&amp;#34;/g&amp;#39; &amp;gt; $out
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;          &amp;#39;&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#fe8019&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#fabd2f&#34;&gt;builtins&lt;/span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;fromTOML (&lt;span style=&#34;color:#fabd2f&#34;&gt;builtins&lt;/span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;readFile theme));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    defaultTheme &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      selection_foreground &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      selection_background &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      foreground &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      background &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color0 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color1 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color2 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color3 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color4 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color5 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color6 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color7 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color8 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color9 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color10 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color11 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color12 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color13 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color14 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      color15 &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      cursor &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      cursor_text_color &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      url_color &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;in&lt;/span&gt; defaultTheme &lt;span style=&#34;color:#fe8019&#34;&gt;//&lt;/span&gt; unwrapKittyTheme (getKittyTheme arg)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;

&lt;p&gt;This function takes a name and matches that against the contents of
&lt;code&gt;pkgs.kitty-themes&lt;/code&gt;. If it fails to find something, it throws an error; If does
find something, it returns that file, converts that to something approach TOML
syntax, which is then parsed using &lt;code&gt;builtins.fromTOML&lt;/code&gt; and merged with a
minimum-viable-colorscheme, ensuring all colors are at the least declared as an
empty string; I ran into issues here when using this output in combination with
Qutebrowser when referring to colors that didn&amp;rsquo;t exist in certain colorschemes.&lt;/p&gt;
&lt;h2 id=&#34;qutebrowser&#34;&gt;Qutebrowser&lt;/h2&gt;
&lt;p&gt;I manage my Qutebrowser config using the &lt;code&gt;home-manager&lt;/code&gt; module (obviously). In
my Qutebrowser config, I have JavaScript disabled by default and use a list of
exception for trusted sites. When I first tried to set this up, I bumped into
the obvious problem that Nix doesn&amp;rsquo;t allow you to bind multiple values to a
single name. Luckily, the Qutebrowser module has an &lt;code&gt;extraConfig&lt;/code&gt; option which
takes a string. At first I had a bunch of lines for those exceptions:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;config.set(&amp;#39;content.javascript.enabled&amp;#39;, True, &amp;#39;https://hoogle.haskell.org/*&amp;#39;)
config.set(&amp;#39;content.javascript.enabled&amp;#39;, True, &amp;#39;https://search.nixos.org/*&amp;#39;)
config.set(&amp;#39;content.javascript.enabled&amp;#39;, True, &amp;#39;https://nix.dev/*&amp;#39;)
config.set(&amp;#39;content.javascript.enabled&amp;#39;, True, &amp;#39;https://voidcruiser.nl/searx/*&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, I quickly got sick of the inherent inefficiency and illegibility of
this approach, so I wrote a few little functions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;programs&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;qutebrowser&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;extraConfig &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;let&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  enableJS &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; url: &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;config.set(&amp;#39;content.javascript.enabled&amp;#39;, True, &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;${&lt;/span&gt;url&lt;span style=&#34;color:#b8bb26&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#39;)&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  javaScriptExceptions &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;https://hoogle.haskell.org/*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;https://search.nixos.org/*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;https://nix.dev/*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;https://voidcruiser.nl/searx/*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#fe8019&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;builtins&lt;/span&gt;; concatStringSep &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#fabd2f&#34;&gt;map&lt;/span&gt; enableJS javaScriptExceptions)&lt;span style=&#34;color:#b8bb26&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;    # things I haven&amp;#39;t managed to abstract properly yet
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;  &amp;#39;&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This takes the contents supplied in &lt;code&gt;javaScriptExceptions&lt;/code&gt; and generates a
viable config line based on each item by mapping over it with the &lt;code&gt;enableJS&lt;/code&gt;
function. Since the Qutebrowser config syntax can&amp;rsquo;t read the nix list syntax,
the items of the resulting list and than concatenated using &lt;code&gt;\n&lt;/code&gt; or a newline
character.&lt;/p&gt;
&lt;h1 id=&#34;xmonad&#34;&gt;XMonad&lt;/h1&gt;
&lt;p&gt;My XMonad configuration has a bunch of weird shit in it, some of which I&amp;rsquo;m proud
of, some of which still has bugs that I keep telling myself I will get to At
Some Point™. Here are some of the nicer bits.&lt;/p&gt;
&lt;h2 id=&#34;volume-control-using-scroll-wheel&#34;&gt;Volume control using scroll wheel&lt;/h2&gt;
&lt;p&gt;I have bound &lt;code&gt;Super + scroll {up,down}&lt;/code&gt; bound to {increase,decrease} volume
respectively.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    , ((modMask, button4), &lt;span style=&#34;color:#fabd2f&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; safeSpawn &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;pulsemixer&amp;#34;&lt;/span&gt; [&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;--change-volume&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;+1&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    , ((modMask, button5), &lt;span style=&#34;color:#fabd2f&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; safeSpawn &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;pulsemixer&amp;#34;&lt;/span&gt; [&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;--change-volume&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;-1&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    , ((modMask &lt;span style=&#34;color:#fe8019&#34;&gt;.|.&lt;/span&gt; shiftMask, button4), &lt;span style=&#34;color:#fabd2f&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; safeSpawn &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;pulsemixer&amp;#34;&lt;/span&gt; [&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;--change-volume&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;+5&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    , ((modMask &lt;span style=&#34;color:#fe8019&#34;&gt;.|.&lt;/span&gt; shiftMask, button5), &lt;span style=&#34;color:#fabd2f&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; safeSpawn &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;pulsemixer&amp;#34;&lt;/span&gt; [&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;--change-volume&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;-5&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The hard part here was coming to the realisation that using a lambda that
discards its argument was the best way to handle interactions while satisfying
the type signature.&lt;/p&gt;
&lt;p&gt;Other than that, these functions are quite straightforward. &lt;code&gt;button4&lt;/code&gt; is &amp;lsquo;scroll
up&amp;rsquo; while &lt;code&gt;button5&lt;/code&gt; is &amp;lsquo;scroll down&amp;rsquo;. I don&amp;rsquo;t recall where I found this, but it
was somewhere in the documentation. As a result, when XMonad registers a
combination of &lt;code&gt;modMask&lt;/code&gt; and either of the scroll directions, it uses
&lt;code&gt;pulsemixer&lt;/code&gt; to increase or decrease the volume.&lt;/p&gt;
&lt;h2 id=&#34;kitty-wrappers&#34;&gt;Kitty wrappers&lt;/h2&gt;
&lt;p&gt;I use the &lt;a href=&#34;https://sw.kovidgoyal.net/kitty/&#34;&gt;Kitty terminal&lt;/a&gt;. Kitty has a huge
feature list, of which I feel like I use about 20% at most. One of these
features is the ability to override config options using the &lt;code&gt;-o&lt;/code&gt; parameter.
This allows you to set a different font(size) or colorscheme or what have you.&lt;/p&gt;
&lt;p&gt;I wanted to be able to start a &lt;code&gt;BQN&lt;/code&gt; repl with the BQN386 font right from my
window manager. So I wrote a few functions that take various arguments and
supply them to Kitty without excessive syntax.&lt;/p&gt;
&lt;p&gt;The simplest one of these is &lt;code&gt;kittyWithOverrides&lt;/code&gt;. It can only take a list of
&lt;code&gt;-o&lt;/code&gt; parameters.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;kittyWithOverrides&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; [&lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt;] &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;kittyWithOverrides&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; spawn &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;kitty &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt;) &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; (unwords &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; map (&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;-o &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here is how I use this function to create a &lt;code&gt;BQN&lt;/code&gt; repl window function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;largeTextBQN&lt;/span&gt; shell &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; [ &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;font_size=17&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     , &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;font_family=&amp;#39;BQN386 Unicode&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     , &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;shell=&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; shell &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;bqn&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; kittyWithOverrides &lt;span style=&#34;color:#fe8019&#34;&gt;$&lt;/span&gt; largeTextBQN &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;bqn&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; I use a &lt;code&gt;largeTextBQN&lt;/code&gt; function rather than a &lt;code&gt;where&lt;/code&gt; binding, because I
use the same settings for a few other repls as well.&lt;/p&gt;
&lt;p&gt;This string will evaluate to the following at compile time:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;kitty -o font_size=17 -o font_family=&amp;#39;BQN386 Unicode&amp;#39; -o shell=&amp;#39;/nix/store/6xwwmv4ljbfckkyklh512zxy6l9s0wv4-cbqn-standalone-0.4.0/bin/bqn&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;…which will then be fed to &lt;code&gt;spawn&lt;/code&gt;, thereby executing it. If I were to spend
more time on it, I could figure out a way to do this properly using &lt;code&gt;safeSpawn&lt;/code&gt;
or one of its variants, but as it stands, I&amp;rsquo;m too lazy to do so.&lt;/p&gt;
&lt;p&gt;For a more general interface I wrote a &lt;code&gt;kittyWithParams&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;kittyWithParams&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; [(&lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt;,&lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt;)] &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;kittyWithParams&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; spawn &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;kitty &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt;) &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; unwords &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; map unwrapParams
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#fe8019&#34;&gt;where&lt;/span&gt; unwrapParams (flag,parameter) &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;case&lt;/span&gt; last flag &lt;span style=&#34;color:#fe8019&#34;&gt;of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                            &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; flag &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; parameter
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                            &lt;span style=&#34;color:#fe8019&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; flag &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; parameter
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Comparatively, it is rather messy. Still, the basic functionality is there and
I&amp;rsquo;m quite happy with how it works.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Emergent Game Mechanics</title>
      <link>/rambles/emergent-mechanics/</link>
      <pubDate>Mon, 25 Sep 2023 02:36:11 +0200</pubDate>
      
      <guid>/rambles/emergent-mechanics/</guid>
      <description>&lt;h1 id=&#34;preamble&#34;&gt;Preamble&lt;/h1&gt;
&lt;p&gt;I usually talk about whatever hobby project I&amp;rsquo;ve been hacking together when the
inspiration to write strikes. In a sense this is a similar ramble, just on a
wildly different topic, namely video game design.&lt;/p&gt;
&lt;h1 id=&#34;the-meat-and-potatoes&#34;&gt;The Meat and Potatoes&lt;/h1&gt;
&lt;p&gt;For some time now I&amp;rsquo;ve been attempting to wrap my head around why I find games
like Doom Eternal to be boring, while games like Ultrakill and Quake are some of
my favourites of all time. And I think I&amp;rsquo;ve found the answer.&lt;/p&gt;
&lt;p&gt;Doom Eternal has location based damage and various enemy weak spots. For
instance, shooting the Mancubus&amp;rsquo; arm cannons causes them to be disabled, making
the Mancubus significantly more manageable. Likewise, shooting a grenade at a
Cacodemon causes it swallow the grenade and be stunned for an easy Glory Kill.
The Arachnotron has a turret that can be shot and disabled; the Makyr Drones can
be shot in the head as quick ammo piñatas; the shields on the dudes carrying
them can be easily disabled using the Plasma Rifle, causing a shock wave&amp;hellip; so
on and so forth.&lt;/p&gt;
&lt;p&gt;Initially, I found these to be really neat ideas. However, it rather quickly
became boring when I found out shooting the weak spots is really the only viable
way to get rid of enemies, especially on higher difficulties. Sure, Doom Eternal
allows you to be very creative in &lt;em&gt;how&lt;/em&gt; you shoot those weak spots, but the
moment you stop bothering with them, the difficulty curve starts to resemble
something closer to a vertical line than an actual curve. The end result is that
the combat feels pre-baked and static if you want to be remotely efficient.&lt;/p&gt;
&lt;p&gt;Ultrakill does this right. It has &amp;ndash; as far as I&amp;rsquo;m aware &amp;ndash; two ways the
trajectory of projectiles can be influenced. One being by punching a projectile
as it is about to hit you. The other is with a shock wave, often caused by an
explosion. Shock waves can be caused using the Knuckleduster (heavy melee
attack), the Core Eject (shotgun altfire that shoots a grenade), the rocket
launcher, parrying your own shotgun blast as it exists the barrel and several
that I can&amp;rsquo;t think of right now. This is the only rule regarding projectiles
that is set in stone. Because of this simplicity and how many enemies have
projectile attacks, you can get very creative in how you kill them, while
keeping all approaches equally viable at any given moment. When an enemy has
just shot a projectile at you, you can chose to dodge it, answer it with a
shotgun blast; punch it back to the culprit using a light melee attack; switch
to heavy melee and shoot it back using a shock wave; overcharge the pump action
shotgun, dodge out of its explosion damage using the I-frames received when
dodging, while using said same explosion to send the projectile back to the
unsuspecting enemy; use those I-frames from the dodge to go through the
projectile and punch the enemy in the face retrieving some health in the
process, etc, etc.&lt;/p&gt;
&lt;p&gt;All of these are viable stratagies depending on how much health you still have
and how many other enemies there are. Getting out of the way of overcharge
explosion damage by dodging is no small feat, but might save you from more
damage if you&amp;rsquo;re surrounded by a lot of high level enemies. Punching a single
enemy isn&amp;rsquo;t something you&amp;rsquo;ll want to do when still surrounded as it means doing
less damage in that moment and only damaging a single enemy. I could go on and
on, describing how and when one might chose any given strategy, but I&amp;rsquo;ll try to
stop here.&lt;/p&gt;
&lt;p&gt;The result is an incredibly dynamic combat system that allows for endless
creativity in dealing with any given scenario. If Ultrakill&amp;rsquo;s design philosophy
were closer to that of Doom Eternal, there would be a dedicated &amp;ldquo;redirect
projectile&amp;rdquo; button/weapon. It wouldn&amp;rsquo;t serve much of a purpose outside of
deflecting the occasional projectile. On top of that, each enemy attack would
have one and only one viable way to answer it.&lt;/p&gt;
&lt;p&gt;For me an encounter in Doom Eternal would go something like the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mancubus, take out its cannons using machine gun altfire; Arachnotron, ditto;
Cacodemon, switch to shotgun, shoot grenade using altfire, Glory Kill; &amp;ldquo;oh
hey, shield dudes&amp;rdquo;, switch to Plasma Rifle and pepper them a bit&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is (usually) one &amp;ldquo;proper&amp;rdquo; strategy to deal with each enemy. As a result,
instead of improvising throughout the entire fight, I&amp;rsquo;m focussing on what hoops
to jump through and in what order. And I guess I don&amp;rsquo;t like being treated as a
circus lion. In Ultrakill, I just do what comes natural in any given situation
without feeling like I&amp;rsquo;m being forced down a rather
face-paced-yet-impressively-boring path.&lt;/p&gt;
&lt;p&gt;Doom Eternal&amp;rsquo;s movement is even more strict. There is a double jump, double dash
and later on a grapple hook. Sure, there are some interesting things you can do
here, but short of exploiting the physics engine by manipulating the framerate
by opening the weapon wheel, you&amp;rsquo;re not going to see any crazy movement
strategies.&lt;/p&gt;
&lt;p&gt;Ultrakill has a triple dash, a slide, dash jump, ground pound and the player
character can be knocked about by explosions and shock waves. On top of that,
there is also the very intricate interplay between these elements due to how the
physics engine works.&lt;/p&gt;
&lt;p&gt;The result here is a set of extremely complex mechanics that are never set in
stone; instead emerging from a few laws of the game that don&amp;rsquo;t have total death
grip control over their domain.&lt;/p&gt;
&lt;p&gt;There is no way I could write an article about emergent mechanics without
mentioning Quake. So lets do that now.&lt;/p&gt;
&lt;p&gt;None of the high level mechanics in Quake are intended. Everything from
straferunning, to wallrunning, to rocket jumping, to bunnyhopping and power
bunnyhopping (also called strafejumping in the context of Quake) is the result
of a few basic rules and wack physics.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;ldquo;The player can turn&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The player can move in 8 cardinal directions&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The player can jump&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The player can sprint, increasing their speed&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;There are entities that are affected by physics&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The player is one such entity&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that&amp;rsquo;s it as far as I&amp;rsquo;m aware.&lt;/p&gt;
&lt;p&gt;All the of the complex movement mechanics emerge from the interplay of these
rules. One of the first that was found was straferunning. What this means is
sending both a move-forward and strafe input. Due to the way velocity is
calculated, this results in a slight speed increase. Shortly after this, it was
discovered that doing this while running into a wall causes a greater speed
increase. As did wiggling the mouse left and right. When jumping you don&amp;rsquo;t lose
any momentum. Put all of these together &amp;ndash; with the exception of wallrunning &amp;ndash;
add little finesse on top and the result is strafejumping.&lt;/p&gt;
&lt;p&gt;To me there is something about using these emergent mechanics that is infinitely
more satisfying than the pre baked equivalents in modern games. Figuring out how
to (ab)use the game&amp;rsquo;s rules to your advantage is half the fun if you ask me and
games like Doom Eternal take most of that away from you by giving you one or
very few viable strategies to approach a given situation and then telling you
most of them from the get go.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Orca</title>
      <link>/rambles/orca/</link>
      <pubDate>Sat, 09 Sep 2023 15:59:21 +0200</pubDate>
      
      <guid>/rambles/orca/</guid>
      <description>&lt;h1 id=&#34;brainy-music&#34;&gt;Brainy Music&lt;/h1&gt;
&lt;p&gt;There&amp;rsquo;s something I really like about the idea of mathematically and
programmatically making music. As a result, I&amp;rsquo;ve harboured an interest in
trackers for quite some time, but never got into attempting to actually use one.
In a similar vein, I&amp;rsquo;ve looked at &lt;a href=&#34;https://100r.co/site/orca.html&#34;&gt;Hundred Rabbits&#39;
Orca&lt;/a&gt; every now and then, but once again
couldn&amp;rsquo;t be bothered to figure it out.&lt;/p&gt;
&lt;p&gt;That was until recently, due to unrelated circumstances, I got access to Ableton
Live. This piqued my interest in Orca again and I decided to grit my teeth and
learn the syntax. The result is that I have now produced some blobs of
characters that &amp;ndash; when paired with the right software &amp;ndash; produce some really
interesting noises.&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t go into detail on how everything works as the documentation is easy
enough to read. The syntax is the biggest hurdle.&lt;/p&gt;
&lt;h1 id=&#34;patterns&#34;&gt;Patterns&lt;/h1&gt;
&lt;p&gt;My favourite operator so far is &lt;code&gt;U&lt;/code&gt; &amp;ndash; the eUclidian rhythm operator. It takes a
left and right argument &amp;ndash; lets refer to them as &lt;code&gt;X&lt;/code&gt; and &lt;code&gt;Y&lt;/code&gt; respectively &amp;ndash; and
then attempts to produce a bang &amp;ndash; that is to say pulse on &lt;code&gt;X&lt;/code&gt; out of &lt;code&gt;Y&lt;/code&gt;
frames. So &lt;code&gt;3U8&lt;/code&gt; attempts to produce 3 equally spaced bangs in 8 frames, which
will fail. As a result, it spaces the bangs as close to equal as possible. This
can lead to some really interesting patterns and rhythms.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example of when I wrapped my head around it for the first time:&lt;/p&gt;
&lt;audio controls=&#34;true&#34;&gt;
	&lt;source src=&#34;/audio/orca/plinkinator.flac&#34; type=&#34;audio/flac&#34;&gt;
	Sorry mate, your browser doesn&#39;t support playing audio files.
	&lt;/source&gt;
&lt;/audio&gt;


&lt;p&gt;And the Orca code:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-orca&#34; data-lang=&#34;orca&#34;&gt;..nVC...........
................
5U9..Vn..4U9..Vn
.*:04C....*:03C.
................
3U5..Vn.........
..:05C..........
................
3U8..Vn.........
.*:06C..........
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;rsquo;s a variant with a different synth and where I&amp;rsquo;ve been messing around with
the note being played while recording:&lt;/p&gt;
&lt;audio controls=&#34;true&#34;&gt;
	&lt;source src=&#34;/audio/orca/varied_plinkinator.flac&#34; type=&#34;audio/flac&#34;&gt;
	Sorry mate, your browser doesn&#39;t support playing audio files.
	&lt;/source&gt;
&lt;/audio&gt;


&lt;h1 id=&#34;numbers-and-stuff&#34;&gt;Numbers and stuff&lt;/h1&gt;
&lt;p&gt;Because I suck at basic calculus and have been half arsedly learning BQN, I
wrote a function to get a list of numbers to produce potentially interesting
patterns for the &lt;code&gt;U&lt;/code&gt; operator:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bqn&#34; data-lang=&#34;bqn&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;OrcaList&lt;/span&gt; ← &lt;span style=&#34;color:#fe8019&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;↕&lt;/span&gt;(&lt;span style=&#34;color:#fabd2f&#34;&gt;⊢⋈&lt;/span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;¨&lt;/span&gt;𝕩&lt;span style=&#34;color:#fe8019&#34;&gt;⊸&lt;/span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;÷&lt;/span&gt;)&lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;+↕&lt;/span&gt;𝕩&lt;span style=&#34;color:#fe8019&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function requires a number and returns a list of all possible divisions
from 1 up to the given number.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bqn&#34; data-lang=&#34;bqn&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#fabd2f&#34;&gt;Orcalist&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;┌─                          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;╵ &lt;span style=&#34;color:#fe8019&#34;&gt;⟨&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;9&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;⟩&lt;/span&gt;                   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#fe8019&#34;&gt;⟨&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;4.5&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;⟩&lt;/span&gt;                 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#fe8019&#34;&gt;⟨&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;⟩&lt;/span&gt;                   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#fe8019&#34;&gt;⟨&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;2.25&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;⟩&lt;/span&gt;                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#fe8019&#34;&gt;⟨&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;1.8&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;⟩&lt;/span&gt;                 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#fe8019&#34;&gt;⟨&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;1.5&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;⟩&lt;/span&gt;                 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#fe8019&#34;&gt;⟨&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;7&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;1.2857142857142858&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;⟩&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#fe8019&#34;&gt;⟨&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;8&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;1.125&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;⟩&lt;/span&gt;               
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#fe8019&#34;&gt;⟨&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;9&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;⟩&lt;/span&gt;                   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           ┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Rough Haskell equivalent for readability&amp;rsquo;s sake:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;orcaList&lt;/span&gt; x &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; map ((,) &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; id &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;lt;*&amp;gt;&lt;/span&gt; (x&lt;span style=&#34;color:#fe8019&#34;&gt;/&lt;/span&gt;)) [&lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;..&lt;/span&gt;x]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;recording-from-lmms&#34;&gt;Recording from LMMS&lt;/h1&gt;
&lt;p&gt;Since LMMS puts whatever MIDI notes it gets into a grid (by default at least),
most of the intricacies of timing are lost. As a result, when using LMMS, I use
&lt;code&gt;pw-record&lt;/code&gt; to record the live audio output with timing still intact.&lt;/p&gt;
&lt;p&gt;This audio journey has also lead me to appreciate Pipewire a lot more. In that
regard, I have the following audio stack on NixOS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ config&lt;span style=&#34;color:#fe8019&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt; }: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sound&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  hardware&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;pulseaudio&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  services&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;pipewire &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    alsa&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    alsa&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;support32Bit &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pulse&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    jack&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And I use &lt;code&gt;qwpgraph&lt;/code&gt; as patchbay.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>I2p on NixOS</title>
      <link>/rambles/i2p-on-nixos/</link>
      <pubDate>Thu, 27 Jul 2023 00:21:37 +0200</pubDate>
      
      <guid>/rambles/i2p-on-nixos/</guid>
      <description>&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Recently I&amp;rsquo;ve decided to move most of my hardware over to NixOS. It&amp;rsquo;s been an
amazing experience being able to configure everything OS related from one
central point.&lt;/p&gt;
&lt;p&gt;A few years ago, I discovered &lt;a href=&#34;https://geti2p.net/en/&#34;&gt;i2p&lt;/a&gt;. I really liked the
idea of it; a different darknet than tor with different kinds of people on it &amp;ndash;
more blog oriented. At the time I ran a node on a Raspberry Pi running Debian. I
connected to it using an ssh tunnel over
&lt;a href=&#34;https://yggdrasil-network.github.io/&#34;&gt;Yggdrasil&lt;/a&gt; and used an
&lt;a href=&#34;https://github.com/arkenfox/user.js&#34;&gt;Arkenfox&lt;/a&gt; hardened Firefox profile to
browse around.&lt;/p&gt;
&lt;p&gt;That Raspberry Pi no longer serves as a (har) server. Instead I now have a NixOS
machine churning away. As with a lot of NixOS topics, there isn&amp;rsquo;t a lot
of documentation on configuring i2p. Though truth be told, when comparing it to
the config files I had on Debian, a lot of it was rather self explanatory and
easy to implement in a Nix module.&lt;/p&gt;
&lt;p&gt;What follows is my current setup on my desktop. Initially I set this up as a
test environment, but it works well to the point where I don&amp;rsquo;t really feel the
need to move it to another machine.&lt;/p&gt;
&lt;h1 id=&#34;the-i2p-module&#34;&gt;The i2p module&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;ll be using the &lt;code&gt;i2pd&lt;/code&gt; implementation of the i2p daemon as it requires less
resources than the java implementation and has less features out of the box that
need configuring.&lt;/p&gt;
&lt;p&gt;Since it is safe to assume that the i2p stack is frequently under attack as it
is a darknet protocol, I decided to run it inside of a Nix container. If you
don&amp;rsquo;t want to do this, only declare a &lt;code&gt;services.i2pd&lt;/code&gt; instance.&lt;/p&gt;
&lt;p&gt;With that out of the way, let&amp;rsquo;s declare a basic container environment named
&lt;code&gt;i2pd-container&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt; }: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  containers&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;i2pd-container &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    autoStart &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    config &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; { &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt; }: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      system&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;stateVersion &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;23.05&amp;#34;&lt;/span&gt;; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# If you don&amp;#39;t add a state version, nix will complain at every rebuild&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From here there are a couple of things you can do with your i2p configuration.
My initial goal was to be able to search the i2p net. To that end, the following
will suffice.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# Exposing the nessecary ports in order to interact with i2p from outside the container&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      networking&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;firewall&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;allowedTCPPorts &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#d3869b&#34;&gt;7070&lt;/span&gt; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# default web interface port&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#d3869b&#34;&gt;4447&lt;/span&gt; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# default socks proxy port&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#d3869b&#34;&gt;4444&lt;/span&gt; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# default http proxy port&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      services&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;i2pd &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        address &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# you may want to set this to 0.0.0.0 if you are planning to use an ssh tunnel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        proto &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          http&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          socksProxy&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          httpProxy&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The SOCKS proxy isn&amp;rsquo;t strictly required, but needed when wanting to use anything
else than an HTTP connection to interact with i2p.&lt;/p&gt;
&lt;h2 id=&#34;torrents&#34;&gt;Torrents&lt;/h2&gt;
&lt;p&gt;After a little while, I wanted to see what kinds of &lt;em&gt;linux distros&lt;/em&gt; the i2p
network has to offer, I also enabled &lt;code&gt;services.i2pd.proto.sam&lt;/code&gt; and added the
corresponding default port to the container&amp;rsquo;s firewall in order to get
&lt;a href=&#34;https://xd-torrent.github.io/&#34;&gt;XD&lt;/a&gt; (which can be found in the Nix repo) to
behave properly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      networking&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;firewall&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;allowedTCPPorts &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; [ &lt;span style=&#34;color:#d3869b&#34;&gt;7656&lt;/span&gt; ];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      services&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;i2pd&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;proto&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;sam&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;details&gt;
	&lt;summary&gt;
		Click here to see everything together
	&lt;/summary&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt; }: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  containers&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;i2pd-container &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    autoStart &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    config &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; { &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt; }: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      system&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;stateVersion &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;23.05&amp;#34;&lt;/span&gt;; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# If you don&amp;#39;t add a state version, nix will complain at every rebuild&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# Exposing the nessecary ports in order to interact with i2p from outside the container&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      networking&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;firewall&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;allowedTCPPorts &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#d3869b&#34;&gt;7656&lt;/span&gt; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# default sam port&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#d3869b&#34;&gt;7070&lt;/span&gt; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# default web interface port&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#d3869b&#34;&gt;4447&lt;/span&gt; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# default socks proxy port&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#d3869b&#34;&gt;4444&lt;/span&gt; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# default http proxy port&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      services&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;i2pd &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        address &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# you may want to set this to 0.0.0.0 if you are planning to use an ssh tunnel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        proto &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          http&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          socksProxy&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          httpProxy&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          sam&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;

&lt;h1 id=&#34;tying-it-to-etcnixosconfigurationnix&#34;&gt;Tying it to &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;I have a perhaps somewhat over engineered structure when it comes to adding my
modules to &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I have a &lt;code&gt;/etc/nixos/services&lt;/code&gt; directory with my own modules, one of which being
&lt;code&gt;services.nix&lt;/code&gt;. &lt;code&gt;services.nix&lt;/code&gt; imports all the other modules found in the
directory. From there, &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt; has
&lt;code&gt;./services/services.nix&lt;/code&gt; in it&amp;rsquo;s import section:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ pkgs&lt;span style=&#34;color:#fe8019&#34;&gt;,&lt;/span&gt; config&lt;span style=&#34;color:#fe8019&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt; }: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  imports &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b8bb26&#34;&gt;./hardware-configuration.nix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b8bb26&#34;&gt;./services/services.nix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;/etc/nixos/services/services.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt; }: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  imports &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b8bb26&#34;&gt;./i2pd-container.nix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;browser-profile&#34;&gt;Browser profile&lt;/h1&gt;
&lt;p&gt;The next step was to set up a browser profile. Since Mullvad recently released a
browser, I decided to use it as a basis for my i2p browser.&lt;/p&gt;
&lt;p&gt;To create a new profile in Firefox or any of it&amp;rsquo;s forks, type/paste
&lt;code&gt;about:profiles&lt;/code&gt; in the URL bar and click the &amp;ldquo;Create a New Profile&amp;rdquo; button at
the top. You will then be prompted for a name. I named mine &amp;ldquo;i2p&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Open this profile in a new session and navigate to &lt;code&gt;about:preferencess#general&lt;/code&gt;
and scroll all the way down to &amp;ldquo;Network Settings&amp;rdquo;. In there, check &amp;ldquo;Manual proxy
configuration&amp;rdquo; and &amp;ldquo;Also use this proxy for HTTPS&amp;rdquo;. From there, fill in the
address you used in &lt;code&gt;services.i2pd.address&lt;/code&gt; or the address of the machine you&amp;rsquo;re
tying it to if you&amp;rsquo;re using an ssh tunnel. For ports, use &lt;code&gt;4444&lt;/code&gt; for the HTTP
proxy and &lt;code&gt;4447&lt;/code&gt; for the SOCKS proxy.&lt;/p&gt;
&lt;p&gt;Then move over to &lt;code&gt;about:preferencess#privacy&lt;/code&gt; and scroll down to &amp;ldquo;Security&amp;rdquo;. I
recommend putting it to &amp;ldquo;Safest&amp;rdquo;. If you &lt;em&gt;really need&lt;/em&gt; to run any JavaScript,
you can always add the NoScript icon to your window bar.&lt;/p&gt;
&lt;p&gt;Then scroll a bit further down to &amp;ldquo;HTTPS-Only Mode&amp;rdquo; and disable it, as the i2p
network doesn&amp;rsquo;t use browser level encryption and thus it would only get in the
way.&lt;/p&gt;
&lt;p&gt;As a final step, go to &lt;code&gt;about:config&lt;/code&gt; and set &lt;code&gt;keyword.enabled&lt;/code&gt; to false. This
isn&amp;rsquo;t strictly necessary, but will make your like a whole lot easier when typing
&lt;code&gt;.i2p&lt;/code&gt; domains and not having your browser attempt &amp;ndash; and fail &amp;ndash; to query the
default search engine.&lt;/p&gt;
&lt;h2 id=&#34;desktop-entry-via-home-manager&#34;&gt;&lt;code&gt;.desktop&lt;/code&gt; entry via &lt;code&gt;home-manager&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re using the &lt;code&gt;home-manager&lt;/code&gt;, you can quite easily create a &lt;code&gt;.desktop&lt;/code&gt;
file to make starting your i2p profile more convenient. This is assuming that
have either a full on desktop environment or use some other way of parsing
&lt;code&gt;.desktop&lt;/code&gt; entries such as &lt;code&gt;rofi&lt;/code&gt;&amp;rsquo;s &lt;code&gt;drun&lt;/code&gt; mode.&lt;/p&gt;
&lt;p&gt;I have the following in my &lt;code&gt;$HOME/.config/home-manager/home.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;xdg&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;desktopEntries &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  i2p-browser &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    name &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;i2p Browser&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    genericName &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;Web Browser&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    exec &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;${&lt;/span&gt;pkgs&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;mullvad-browser&lt;span style=&#34;color:#b8bb26&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;/bin/mullvad-browser -p i2p&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Firefox and it&amp;rsquo;s forks allow you to start a session with a profile using the
&lt;code&gt;-p&lt;/code&gt; parameter. Similarly the &lt;code&gt;-P&lt;/code&gt; (that is, an upper case &amp;lsquo;P&amp;rsquo; rather than lower
case) parameter brings up a profiles menu that allows you to easily change the
default profile when running the binary the next time.&lt;/p&gt;
&lt;h1 id=&#34;using-everything&#34;&gt;Using everything&lt;/h1&gt;
&lt;p&gt;After starting the container, wait at least 15 minutes for i2pd to build a few
tunnels before attempting to connect to anything. Once you have, open your
i2p browser profile and you should be able to browse the i2p net. Don&amp;rsquo;t expect
things to be fast however, i2p is a much slower network in my experience than
Tor.&lt;/p&gt;
&lt;p&gt;Some pages to get you started:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://reg.i2p&#34;&gt;reg.i2p&lt;/a&gt; - link index&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://stats.i2p/&#34;&gt;stats.i2p&lt;/a&gt; - link index&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://notbob.i2p/&#34;&gt;notbob.i2p&lt;/a&gt; - link index&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://lmwr2pugnmv4pkkxlneeepi4oysfly33zfuj7x25s6hfydysnpfq.b32.i2p/&#34;&gt;My site&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Ideas</title>
      <link>/ideas/</link>
      <pubDate>Sun, 26 Mar 2023 22:21:28 +0200</pubDate>
      
      <guid>/ideas/</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Car bine&lt;/li&gt;
&lt;li&gt;Gun named Tommy (Chicago mafia accent)&lt;/li&gt;
&lt;li&gt;Pee/Pea shooter&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>XMonad Promtps</title>
      <link>/rambles/xmonad-prompts/</link>
      <pubDate>Wed, 08 Mar 2023 14:20:11 +0100</pubDate>
      
      <guid>/rambles/xmonad-prompts/</guid>
      <description>&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;XMonad has it&amp;rsquo;s own prompt system. Some time ago, I wanted to see if it could
replace dmenu entirely. I managed it for the more common usages I had for it. My
application launcher, &lt;code&gt;ssh&lt;/code&gt; prompt and pass interface were easy to replace using
standard XMonad Contrib modules (&lt;code&gt;XMonad.Prompt.Shell&lt;/code&gt;, &lt;code&gt;XMonad.Prompt.Ssh&lt;/code&gt; and
&lt;code&gt;XMonad.Prompt.Pass&lt;/code&gt; respectively). However, things became more difficult when
it came to my universal/external Qutebrowser bookmarks menu and
&lt;code&gt;yt-dlp&lt;/code&gt;-and-&lt;code&gt;pipe-viewer&lt;/code&gt; wrapper.&lt;/p&gt;
&lt;p&gt;This tutorial-of-sorts will assume &lt;em&gt;some&lt;/em&gt; Haskell knowledge or not being afraid
of diving straight into how Haskell works. I&amp;rsquo;m not going into great detail on
how everything works here.&lt;/p&gt;
&lt;h1 id=&#34;bookmarks-menu&#34;&gt;Bookmarks menu&lt;/h1&gt;
&lt;p&gt;The first one I decided to tackle was the bookmarks menu, as it is by far the
simplest of the two.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s take a look at the original:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8ec07c&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8ec07c&#34;&gt;&lt;/span&gt;bookmarks&lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt;$HOME&lt;span style=&#34;color:#b8bb26&#34;&gt;/.config/qutebrowser/bookmarks/urls&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;choice&lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;$(&lt;/span&gt;awk &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#39;{print$1}&amp;#39;&lt;/span&gt; $bookmarks | sort | dmenu -p &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;Bookmark:&amp;#34;&lt;/span&gt; -l 30&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;[&lt;/span&gt; -z $choice &lt;span style=&#34;color:#fe8019&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;||&lt;/span&gt; qutebrowser &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt;$choice&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Things get interesting at the initialisation of the &lt;code&gt;choice&lt;/code&gt; variable:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It takes the contents of Qutebrowser&amp;rsquo;s bookmarks file&lt;/li&gt;
&lt;li&gt;It sorts the results of that&lt;/li&gt;
&lt;li&gt;Sends that to &lt;code&gt;dmenu&lt;/code&gt;, prompting the user to make a choice&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After this, it checks whether &lt;code&gt;choice&lt;/code&gt; is empty or not and in case it isn&amp;rsquo;t,
opens Qutebrowser with its contents.&lt;/p&gt;
&lt;p&gt;Here is an example of how Qutebrowser saves its bookmarks:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;https://www.alpinelinux.org/ index | Alpine Linux
https://www.openbsd.org/ftp.html OpenBSD: Mirrors
https://commonmark.org/ CommonMark
https://xxiivv.com/ Echorridoors
https://100r.co/site/home.html 100R — home
https://solar.lowtechmagazine.com/about.html About this website | LOW←TECH MAGAZINE
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;implementation&#34;&gt;Implementation&lt;/h2&gt;
&lt;p&gt;Its functionality does boils down to the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Parse a given file according to a set of rules, returning it&amp;rsquo;s contents in
the form of a list&lt;/li&gt;
&lt;li&gt;Allow the user to make a choice from that list&lt;/li&gt;
&lt;li&gt;Launch an application with that choice as parameter&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Seems easy enough to implement.&lt;/p&gt;
&lt;h3 id=&#34;parsing-the-bookmarks-file&#34;&gt;Parsing the Bookmarks file&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s start off by creating a function that can parse our bookmarks file. Here we
need something to read a file &amp;ndash; in this case a bookmarks file &amp;ndash; and return its
contents in the form of a list of strings.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;fileContentList&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;FilePath&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;IO&lt;/span&gt; [&lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function takes a filepath &amp;ndash; the &lt;code&gt;Filepath&lt;/code&gt; datatype is an alias for
&lt;code&gt;String&lt;/code&gt; &amp;ndash; and returns &lt;code&gt;IO [String]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now for the body of the function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;fileContentList&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;FilePath&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;IO&lt;/span&gt; [&lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;fileContentList&lt;/span&gt; f &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    homeDir &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;lt;-&lt;/span&gt; getEnv &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;HOME&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    file &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;lt;-&lt;/span&gt; readFile (homeDir &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; f)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    return &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; uniqSort &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; lines &lt;span style=&#34;color:#fe8019&#34;&gt;$&lt;/span&gt; file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s go over what is happening here line by line.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fileContentList&lt;/code&gt; is a function that takes an argument &lt;code&gt;f&lt;/code&gt;; then it starts a
&lt;code&gt;do&lt;/code&gt; block. &lt;code&gt;do&lt;/code&gt; blocks are used to put multiple functions in sequence in the
scope of a single function without having them interact with eachother.&lt;/p&gt;
&lt;p&gt;Within the &lt;code&gt;do&lt;/code&gt; block, it first retrieves the current home directory based on
the &lt;code&gt;$HOME&lt;/code&gt; environment variable and binds it to &lt;code&gt;homeDir&lt;/code&gt; using the &lt;code&gt;getEnv&lt;/code&gt;
function from the &lt;code&gt;System.Environment&lt;/code&gt; module. &lt;code&gt;getEnv&lt;/code&gt; returns a string with
the contents of the variable given as its argument.&lt;/p&gt;
&lt;p&gt;Next, it retrieves the file contents from &lt;code&gt;$HOME/path/to/file&lt;/code&gt; using the
&lt;code&gt;readFile&lt;/code&gt;. This path is created by appending &lt;code&gt;f&lt;/code&gt; to the &lt;code&gt;homeDir&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now for the final line.&lt;/p&gt;
&lt;p&gt;First it takes the &lt;code&gt;file&lt;/code&gt; and splits it up into a list of strings based on
newlines using the &lt;code&gt;lines&lt;/code&gt; function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    lines &lt;span style=&#34;color:#fe8019&#34;&gt;$&lt;/span&gt; file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then it pipes the result from that into &lt;code&gt;uniqSort&lt;/code&gt; from the &lt;code&gt;XMonad.Prompt&lt;/code&gt;
module in order to &amp;ndash; as the name implies &amp;ndash; sort it and get rid of any
duplicate items.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    uniqSort &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; lines &lt;span style=&#34;color:#fe8019&#34;&gt;$&lt;/span&gt; file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the output of that is piped into &lt;code&gt;return&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    return &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; uniqSort &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; lines &lt;span style=&#34;color:#fe8019&#34;&gt;$&lt;/span&gt; file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function will allow us to parse any given text file. To parse the
Qutebrowser bookmarks file, call it using &lt;code&gt;.config/qutebrowser/bookmarks/url&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: I say &amp;ldquo;pipe&amp;rdquo; because the &amp;lsquo;&lt;code&gt;.&lt;/code&gt;&amp;rsquo; function behaves quite similar to
pipes in POSIX Shell. However, the correct way of referring to what it does
is composition; it takes two functions and passes the output of the first
function to the second, thereby creating &amp;ndash; or composing a new function. As
apposed to how pipes in POSIX Shell work, function composition chains are
executed from right to left.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;creating-a-prompt&#34;&gt;Creating a Prompt&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s see if there is anything in the
&lt;a href=&#34;https://hackage.haskell.org/package/xmonad-contrib-0.17.1/docs/XMonad-Prompt.html&#34;&gt;&lt;code&gt;XMonad.Prompt&lt;/code&gt;&lt;/a&gt;
module that looks like it could help us in creating a prompt.&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;mkXPrompt&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;XPrompt&lt;/span&gt; p &lt;span style=&#34;color:#fe8019&#34;&gt;=&amp;gt;&lt;/span&gt; p &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;XPConfig&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;ComplFunction&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;()&lt;/span&gt;) &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;p&gt;Creates a prompt given:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a prompt type, instance of the &lt;code&gt;XPrompt&lt;/code&gt; class.&lt;/li&gt;
&lt;li&gt;a prompt configuration (&lt;code&gt;def&lt;/code&gt; can be used as a starting point)&lt;/li&gt;
&lt;li&gt;a completion function (&lt;code&gt;mkComplFunFromList&lt;/code&gt; can be used to create a completions function given a list of possible completions)&lt;/li&gt;
&lt;li&gt;an action to be run: the action must take a string and return &lt;code&gt;X ()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;This looks like it could serve as the basis for our prompt. The description and
type signature tell us that it is going to require an instance of the &lt;code&gt;XPrompt&lt;/code&gt;
typeclass. So let&amp;rsquo;s create a &lt;code&gt;Bookmark&lt;/code&gt; datatype and implement the &lt;code&gt;showXPrompt&lt;/code&gt;
function from &lt;code&gt;XPrompt&lt;/code&gt; in order to give it a default message when executed and
thereby having it derive from &lt;code&gt;XPrompt&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;instance&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;XPrompt&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    showXPrompt &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;Bookmark: &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As its second argument, &lt;code&gt;mkXPrompt&lt;/code&gt; requires an instance of &lt;code&gt;XPConfig&lt;/code&gt;. The
&lt;code&gt;XPConfig&lt;/code&gt; typeclass is where you &amp;ndash; as the name implies &amp;ndash; specify the
configuration of XMonad&amp;rsquo;s prompts. Knowing this we can start to write function that
uses &lt;code&gt;mkXPrompt&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;bookmarkPrompt&lt;/span&gt; c &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mkXPrompt &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt; c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;c&lt;/code&gt; is our &lt;code&gt;XPConfig&lt;/code&gt; argument.&lt;/p&gt;
&lt;p&gt;This takes care of the &lt;code&gt;XPrompt p =&amp;gt; p -&amp;gt; XPConfig&lt;/code&gt; portion of the function.&lt;/p&gt;
&lt;p&gt;Now for the completion function, that will handle the list given to our prompt.
Let&amp;rsquo;s mostly follow the suggestion in the description of &lt;code&gt;mkXPrompt&lt;/code&gt; and lets
take a look at:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;mkComplFunFromList&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;XPConfig&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; [&lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt;] &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;IO&lt;/span&gt; [&lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;p&gt;This function takes a list of possible completions and returns a completions
function to be used with mkXPrompt. If the string is null it will return all
completions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is how Qutebrowser and &lt;code&gt;dmenu&lt;/code&gt; act by default with a given list of possible
options.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;bookmarksFile&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;.config/qutebrowser/bookmarks/urls&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;I didn&amp;rsquo;t know where to put this, but I created a string to hold the path to my
bookmarks&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So it takes an instance of &lt;code&gt;XPConfig&lt;/code&gt; &amp;ndash; that will again be our &lt;code&gt;c&lt;/code&gt; argument,
and a list of strings. Here is where we feed it the contents of our file using
our &lt;code&gt;fileContentList&lt;/code&gt; function. We will do this by binding the output to, say
&lt;code&gt;bl&lt;/code&gt; for &amp;ldquo;bookmark list&amp;rdquo; with &lt;code&gt;&amp;lt;-&lt;/code&gt;. Since &lt;code&gt;fileContentList&lt;/code&gt; is a member of the
&lt;code&gt;IO&lt;/code&gt; monad and we&amp;rsquo;re working in, we have to call it using the &lt;code&gt;io&lt;/code&gt; function,
which is an alias for the &lt;code&gt;liftIO&lt;/code&gt; function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;bookmarkPrompt&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;XPConfig&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;()&lt;/span&gt;) &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;bookmarkPrompt&lt;/span&gt; c f &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bl &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;lt;-&lt;/span&gt; io fileContentList bookmarksFile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mkXPrompt &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt; c (mkComplFunFromList&amp;#39; c bl) f
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You&amp;rsquo;ll see that I&amp;rsquo;ve also added argument &lt;code&gt;f&lt;/code&gt;, this is the function we&amp;rsquo;re going
to use to actually do something with our prompt output. Considering we&amp;rsquo;re
working with bookmarks, opening them in a browser would make sense.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;openBookmark&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;openBookmark&lt;/span&gt; bookmark &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    browser &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;lt;-&lt;/span&gt; io getBrowser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    spawn &lt;span style=&#34;color:#fe8019&#34;&gt;$&lt;/span&gt; browser &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34; &amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; getUrl bookmark &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#fe8019&#34;&gt;where&lt;/span&gt; getUrl &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; head &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; words
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;openBookmark&lt;/code&gt; is a function that takes a string and returns something in the
context of the &lt;code&gt;X&lt;/code&gt; monad (hence the name &amp;ldquo;XMonad&amp;rdquo;, it&amp;rsquo;s a monad that interacts
with Xorg). Let&amp;rsquo;s go through it line by line.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    browser &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;lt;-&lt;/span&gt; io getBrowser
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First we get user&amp;rsquo;s browser using the &lt;code&gt;getBrowser&lt;/code&gt; function from the
&lt;code&gt;XMonad.Prompt.Shell&lt;/code&gt; module and bind that to &lt;code&gt;browser&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This function checks the &lt;code&gt;$BROWSER&lt;/code&gt; environment variable and if it isn&amp;rsquo;t set, it
defaults to &amp;ldquo;firefox&amp;rdquo;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    spawn &lt;span style=&#34;color:#fe8019&#34;&gt;$&lt;/span&gt; browser &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34; &amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; getUrl bookmark &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since &lt;code&gt;getBrowser&lt;/code&gt; returns a string, we can append things to it and feed that to
&lt;code&gt;spawn&lt;/code&gt;. In this case, we get the URL portion of the bookmark entry surrounded by
single quotes in case a given bookmark contains any symbols that mess up our
shell. After all, what &lt;code&gt;spawn&lt;/code&gt; ultimately does is feed a given string to
&lt;code&gt;/bin/sh&lt;/code&gt; as a command to execute.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#fe8019&#34;&gt;where&lt;/span&gt; getUrl &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; head &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; words
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For get &lt;code&gt;getUrl&lt;/code&gt;, we take the given string, split it into a list of strings
based on space characters, pipe that into head, thus retrieving the first item.&lt;/p&gt;
&lt;h2 id=&#34;keybinding&#34;&gt;Keybinding&lt;/h2&gt;
&lt;p&gt;We now have a set of functions that create a prompt populated with our
Qutebrowser bookmarks file (any other list of URLs will also work) which will
open our browser when choosing one.&lt;/p&gt;
&lt;p&gt;Now all we have to do is bind it to a key. Personally I use the
&lt;code&gt;XMonad.Util.EZConfig&lt;/code&gt; so I have the following in my keybindings:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;, (&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;M-M1-C-b&amp;#34;&lt;/span&gt;, bookmarkPrompt (myXPConfig {autoComplete &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;Just&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;200000&lt;/span&gt;}) openBookmark &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you use the default way of defining keybindings you can use something like
the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;, ((modm &lt;span style=&#34;color:#fe8019&#34;&gt;.|.&lt;/span&gt; controlMask, xK_b), bookmarkPrompt def openBookmark)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;def&lt;/code&gt; is a reference to the default implementation of &lt;code&gt;XPConfig&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&#34;everything-together&#34;&gt;Everything Together&lt;/h1&gt;
&lt;p&gt;Everything put together, your config should have something like the following
added.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;instance&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;XPrompt&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    showXPrompt &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;Bookmark: &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;bookmarksFile&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;.config/qutebrowser/bookmarks/urls&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;fileContentList&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;FilePath&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;IO&lt;/span&gt; [&lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;fileContentList&lt;/span&gt; f &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    homeDir &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;lt;-&lt;/span&gt; getEnv &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;HOME&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    file &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;lt;-&lt;/span&gt; readFile (homeDir &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; f)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    return &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; uniqSort &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; lines &lt;span style=&#34;color:#fe8019&#34;&gt;$&lt;/span&gt; file
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;bookmarkPrompt&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;XPConfig&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;()&lt;/span&gt;) &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;bookmarkPrompt&lt;/span&gt; c f &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bl &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;lt;-&lt;/span&gt; io fileContentList bookmarksFile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mkXPrompt &lt;span style=&#34;color:#fabd2f&#34;&gt;Bookmark&lt;/span&gt; c (mkComplFunFromList&amp;#39; c bl) f
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;openBookmark&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;openBookmark&lt;/span&gt; bookmark &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    browser &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;lt;-&lt;/span&gt; io getBrowser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    spawn &lt;span style=&#34;color:#fe8019&#34;&gt;$&lt;/span&gt; browser &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34; &amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; getUrl bookmark &lt;span style=&#34;color:#fe8019&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#fe8019&#34;&gt;where&lt;/span&gt; getUrl &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; head &lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt; words
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;-- ... keybindings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;, ((modm &lt;span style=&#34;color:#fe8019&#34;&gt;.|.&lt;/span&gt; controlMask, xK_b), bookmarkPrompt def openBookmark)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;-- more keybindings ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>On window managers and XMonad</title>
      <link>/rambles/windowmanagers/</link>
      <pubDate>Thu, 03 Nov 2022 23:17:35 +0100</pubDate>
      
      <guid>/rambles/windowmanagers/</guid>
      <description>&lt;h1 id=&#34;my-journey-into-tiling-window-managers&#34;&gt;My journey into Tiling Window Managers&lt;/h1&gt;
&lt;p&gt;When I started my Linux journey, I stuck with GNOME 3 something for around the
first year. Sure, I tried KDE and Cinnamon and XFCE, but GNOME is the one I
always kept coming back to. I think it&amp;rsquo;s because it&amp;rsquo;s pretty much the only one
that felt completely different from what the rest of the world was doing. It
helped me with thinking about Linux as being different from windows. After this
first year though, I came across a few videos about tiling window managers and
wanted to try one. The first one I installed was &lt;a href=&#34;https://i3wm.org/&#34;&gt;i3&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I hated it.&lt;/p&gt;
&lt;p&gt;I had a hard time configuring it as I didn&amp;rsquo;t really know what I was doing.
Other than that, I found it plain awkward to use. The way it tiles windows &amp;ndash;
and how you &lt;em&gt;still&lt;/em&gt; have to babysit pretty much every last one of them &amp;ndash;
drives me away from i3 to this day. I&amp;rsquo;m sure it has the potential to be a great
window manager. It&amp;rsquo;s just &lt;em&gt;really&lt;/em&gt; not for me. Which is a shame, I would really
like to properly live in Wayland with &lt;a href=&#34;https://swaywm.org/&#34; title=&#34;Sway is like
i3 in Wayland&#34;&gt;Sway&lt;/a&gt; for at least a little while.&lt;/p&gt;
&lt;p&gt;After a few hours of trying to get things to work in i3, I went back to GNOME.
Some time later, I came across &lt;a href=&#34;https://awesomewm.org/&#34;&gt;AwesomeWM&lt;/a&gt;. It was
being recommended as a fairly easy window manager to start with &amp;ndash; it having
window decorations and it&amp;rsquo;s own menu system. The first thing I did was try-and
fail to rip out said menu system and window decorations. I was putting too much
on myself trying to learn the basics of both using a tiling window manager and
Lua.&lt;/p&gt;
&lt;p&gt;Some time after that, I came across
&lt;a href=&#34;https://github.com/baskerville/bspwm&#34;&gt;BSPWM&lt;/a&gt;. This was the first time where I
felt like I &lt;em&gt;really&lt;/em&gt; managed to get a tiling window manger to do what I wanted
it to do. For some odd reason, there are people out there who consider BSPWM a
more &amp;ldquo;advanced&amp;rdquo; window manger. I really don&amp;rsquo;t get why. To this day, I am of the
opinion that SXHKD&amp;rsquo;s configuration syntax is some of the best out there. I
think it took me around 10 minutes to wrap my head around the basics. Somewhere
around an afternoon later, I had a config that served me well for the next few
months to come.&lt;/p&gt;
&lt;p&gt;A while after BSPWM, I decided to give suckless&#39;
&lt;a href=&#34;https://dwm.suckless.org/&#34;&gt;DWM&lt;/a&gt; a shot. Despite my lack of knowledge of C,
this very quickly became my favorite window manager at the time. There is just
something about the insanity of using diff files to configure your piece of
software when perfectly functional configuration libraries and languages exist
that got it&amp;rsquo;s hooks in me. I also caught the minimalism bug around this time,
so DWM&amp;rsquo;s nearly non-existent memory footprint was also great. Despite this
really being the first really &amp;ldquo;advanced&amp;rdquo; window manager, I had an easier time
configuring it than AwesomeWM or i3. It was also the first time where I could
appreciate the master-stack layout properly and not having to think about
keeping track of windows in two dimensions anymore. It made me realise that I
want to have to think as little as possible about window positioning. It was
the reason I couldn&amp;rsquo;t deal with i3&amp;rsquo;s paradigm and shifted away from BSPWM the
moment I found DWM.&lt;/p&gt;
&lt;p&gt;I ran DWM as my main window manger for over a year before having issues with
some fullscreen applications and the JetBrains suite, which I had to use for
college activities.&lt;/p&gt;

&lt;figure &gt;&lt;a href=&#34;https://xkcd.com/1806/&#34;&gt;&lt;img src=&#34;/images/xkcd/borrow_your_laptop.png&#34;&gt;&lt;/a&gt;&lt;/figure&gt;

&lt;p&gt;I decided to give AwesomeWM another shot after having figured out what I want
from a tiling window manger. This time I managed to get something that worked
pretty much exactly how I wanted it to. In other words, a fairly basic
configuration with most of the default features ripped out and instead my
partially-organically-grown-probably-batshit-insane-keybindings (I use &lt;code&gt;Super&lt;/code&gt; +
&lt;code&gt;Space&lt;/code&gt; to open my run launcher. In fact, on my keyboard I have holding the big
space bar (yes it has two space bars, its layout is about as insane as my
window management keybindings) bound to &lt;code&gt;Super&lt;/code&gt; + &lt;code&gt;Space&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;To this day I still use DWM quite frequently on machines where I don&amp;rsquo;t really
want to think about what graphical interface to chuck on it (hence I half
arsedly maintain an Alpine package of my fork).&lt;/p&gt;
&lt;p&gt;For quite a long time I used DWM and AwesomeWM depending on whether I was
planning on frequently using fullscreen applications and how strong the machine
in question was; AwesomeWM being noticeably slower than DWM on &lt;em&gt;really&lt;/em&gt; old
machines (like RejuvinatedBrick). Until at some point, I came across
&lt;a href=&#34;https://xmonad.org/&#34;&gt;XMonad&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I tried it for an evening.&lt;/p&gt;
&lt;p&gt;I hated the fact that it&amp;rsquo;s configured in &lt;em&gt;sodding Haskell&lt;/em&gt; and went back to DWM.&lt;/p&gt;
&lt;p&gt;A few months later, I came across an implementation of chorded keys through
the &lt;code&gt;XMonad.Util.EZConfig&lt;/code&gt; module and decided to give it another shot.&lt;/p&gt;
&lt;p&gt;This time I was hooked.&lt;/p&gt;
&lt;p&gt;The biggest problem I had with it was &lt;em&gt;still&lt;/em&gt; the fact that it was configured
in Haskell, but the absurd level of customisability made it worth dealing with
the functional pain. It was also the first time I decided to not bother with a
status bar as getting a basic configuration going had given me enough grief for
one month.&lt;/p&gt;
&lt;p&gt;As for gripes I had (and partially still have) with XMonad, they were quite few,
surprisingly. Coming from AwesomeWM and DWM, I would&amp;rsquo;ve liked XMonad to use tags
instead of workspaces; fullscreen is a bit of a pain to get working, but has
less fuckups than DWM; the fact that it&amp;rsquo;s configured in Haskell; it not having a
set of workspaces per monitor (at least by default, I kind of stopped caring
after a little while); the fact that it&amp;rsquo;s configured in Haskell; the
&lt;code&gt;XMonad.Layout.ShowWName&lt;/code&gt; module being kind of unstable and last but not least,
the fact that it&amp;rsquo;s configured in &lt;em&gt;fucking Haskell&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It almost seems like I got sick of being sick of it being configured in Haskell
and I decided to dive into learning the language with the goal of being able to
fully understand my monstrous 384 line config file (586 lines including the
documentation in commented sections).&lt;/p&gt;

&lt;figure &gt;&lt;img src=&#34;/images/config_length.png&#34;&gt;&lt;/figure&gt;

&lt;p&gt;I don&amp;rsquo;t fully understand it yet at the time of writing, but I do understand it
a hell of a lot better than when I produced most of those 300 lines.&lt;/p&gt;
&lt;p&gt;The greatest thing about XMonad is simultaneously the thing that kept me away
from it: it&amp;rsquo;s written and configured in bloody Haskell. Thus there is barely a
separation between configuration and source code. The only difference there
&lt;em&gt;really&lt;/em&gt; is, is the filename. Once you understand a bit of Haskell (no small
task if you&amp;rsquo;re used to imperative languages) adding and integrating your own
features is really easy. And then they are &lt;em&gt;properly&lt;/em&gt; integrated. Sort of like
how DWM works, only with proper documentation and support. Part of me wants to
see if I can figure out a way to package my XMonad build as a single binary to
be able to chuck it onto systems without putting much thought into it.&lt;/p&gt;
&lt;p&gt;Weird thing with Haskell I&amp;rsquo;m noticing so far is that I&amp;rsquo;m slowly but surely
managing to dig up old concepts that I tried to implement in imperative
languages, but couldn&amp;rsquo;t due to their nature. Things like pattern matching and
maps are quite intuitive to me. It&amp;rsquo;s just that Haskell&amp;rsquo;s syntax takes a &lt;em&gt;lot&lt;/em&gt; of
getting used to. In the mean time, I guess that my experience with POSIX Shell
bridged the gap between my knowledge of Go and C#; and Haskell.&lt;/p&gt;
&lt;p&gt;I highly recommend giving XMonad a shot if you&amp;rsquo;re willing to bash your head
against the Haskell wall for a while before understanding how your window
manager works.&lt;/p&gt;
&lt;p&gt;Looking back I find it quite funny to see how I went from not being able to get
i3 to do what I wanted it too and giving up; to barely being able to write or
understand Haskell but putting up with it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>PWR Switch</title>
      <link>/rambles/pwr-switch/</link>
      <pubDate>Fri, 14 Oct 2022 10:50:56 +0200</pubDate>
      
      <guid>/rambles/pwr-switch/</guid>
      <description>&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;As we all know, the &amp;ldquo;S&amp;rdquo; in IOT stands for security.
We&amp;rsquo;ve all seen countless stories of people&amp;rsquo;s networks getting hijacked due to some 3 year old vulnerability in the software stack of their &lt;em&gt;insert smart device here&lt;/em&gt;.
These things barely get any patches at all.
On top of that, the most they do is spy on you and send &lt;a href=&#34;https://edition.cnn.com/2022/07/14/tech/amazon-ring-police-footage/index.html&#34; title=&#34;Load without JS to make the page behave.&#34;&gt;your footage to the police without asking for your consent&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Still, on the other hand, it can be really convenient to be able to control some of the electronics in your home without having to walk towards them.
I personally have a lamp that I frequently forget to turn off when leaving my room.
The solution was an &lt;a href=&#34;https://www.olimex.com/Products/Duino/Shields/PWR-SWITCH/&#34;&gt;Olimex PWR-switch&lt;/a&gt; in combination with a Raspberry Pi 4 that I have running 24/7 regardless (mostly to watch YouTube videos and listen to music over my speaker set; I might write a post about this beautifully hacky contraption at some point in the future).&lt;/p&gt;
&lt;h1 id=&#34;setup&#34;&gt;Setup&lt;/h1&gt;
&lt;p&gt;Setting it up was relatively easy.&lt;/p&gt;
&lt;p&gt;First I connected a European extension socket to a random 230 volt cable I still had laying around.
Then I hooked that up to my PWR-switch and plugged my lamp into that contraption.&lt;/p&gt;
&lt;p&gt;From there I got little bag of jumper wires from my local electronics store and hooked up the PWR-switch to my Raspberry Pi.
I hooked up the PWR-switch&amp;rsquo;s positive to &lt;code&gt;GPIO 15&lt;/code&gt; and it&amp;rsquo;s ground to the preceding &lt;code&gt;ground&lt;/code&gt; pin.
&lt;a href=&#34;https://pinout.xyz&#34;&gt;Here&amp;rsquo;s&lt;/a&gt; a reference page.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;, &lt;code&gt;GPIO 15&lt;/code&gt; is in reference to pin number 10 and the preceding ground pin is pin number 6.&lt;/p&gt;
&lt;p&gt;From there I looked up how to send power to &lt;code&gt;GPIO 15&lt;/code&gt; in order to have it toggle to the &amp;ldquo;on&amp;rdquo; state.
The first step to this end is to initialise the pin.
This can be done with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;15&lt;/span&gt; &amp;gt; /sys/class/gpio/export
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; out &amp;gt; /sys/class/gpio/gpio15/direction
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, sending power to it can be done using something like&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio15/value
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip;and the opposite can be done using:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;0&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio15/value
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Deinitialising the pin can be done with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;15&lt;/span&gt; &amp;gt; /sys/class/gpio/unexport
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To make this all a little easier I have written a wrapper in POSIX Shell:
&lt;details&gt;
	&lt;summary&gt;
		Click to see script
	&lt;/summary&gt;
&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8ec07c&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8ec07c&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INIT_PIN&lt;span style=&#34;color:#fe8019&#34;&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# the PWR-SWITCH is connected to GPIO 15 and the preceding ground pin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# reference page https://pinout.xyz/pinout/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fe8019&#34;&gt;[&lt;/span&gt; -d /sys/class/gpio/gpio15 &lt;span style=&#34;color:#fe8019&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;Pin already initialised&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;exit&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;15&lt;/span&gt; &amp;gt; /sys/class/gpio/export
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; out &amp;gt; /sys/class/gpio/gpio15/direction
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DEINIT_PIN&lt;span style=&#34;color:#fe8019&#34;&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fe8019&#34;&gt;[&lt;/span&gt; -d /sys/class/gpio/gpio15 &lt;span style=&#34;color:#fe8019&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;Pin not initialised&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;exit&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;15&lt;/span&gt; &amp;gt; /sys/class/gpio/unexport
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PIN_STATUS&lt;span style=&#34;color:#fe8019&#34;&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fe8019&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;[&lt;/span&gt; -d /sys/class/gpio/gpio15 &lt;span style=&#34;color:#fe8019&#34;&gt;]&lt;/span&gt; ; &lt;span style=&#34;color:#fe8019&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;pin status: Pin initialised&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fe8019&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;pin status: Pin not initialised&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fe8019&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SWITCH_ON&lt;span style=&#34;color:#fe8019&#34;&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# initialise pin before doing anything&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fe8019&#34;&gt;[&lt;/span&gt; -d /sys/class/gpio/gpio15 &lt;span style=&#34;color:#fe8019&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;||&lt;/span&gt; INIT_PIN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio15/value
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SWITCH_OFF&lt;span style=&#34;color:#fe8019&#34;&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# initialise pin before doing anything&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fe8019&#34;&gt;[&lt;/span&gt; -d /sys/class/gpio/gpio15 &lt;span style=&#34;color:#fe8019&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;||&lt;/span&gt; INIT_PIN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;0&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio15/value
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TOGGLE_SWITCH&lt;span style=&#34;color:#fe8019&#34;&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# initialise pin before doing anything&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fe8019&#34;&gt;[&lt;/span&gt; -d /sys/class/gpio/gpio15 &lt;span style=&#34;color:#fe8019&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;||&lt;/span&gt; INIT_PIN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fe8019&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;$(&lt;/span&gt;cat /sys/class/gpio/gpio15/value&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt; in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		1&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt; SWITCH_OFF;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		0&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt; SWITCH_ON;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#fe8019&#34;&gt;esac&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;USAGE&lt;span style=&#34;color:#fe8019&#34;&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	cat &amp;gt;&amp;amp;&lt;span style=&#34;color:#d3869b&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;Usage: pwr-switch &amp;lt;on|off|init|deinit&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;	on: send on signal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;	off: send off signal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;	init: initialise pin
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;	deinit: deinitialise pin
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;	status: show pin initialisation state
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;	toggle: toggle on/off signal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;case&lt;/span&gt; $1 in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	on&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt; SWITCH_ON;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	off&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt; SWITCH_OFF;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	init&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt; INIT_PIN;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	deinit&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt; DEINIT_PIN;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	status&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt; PIN_STATUS;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	toggle&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt; TOGGLE_SWITCH;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	*&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt; USAGE;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;esac&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;

&lt;p&gt;You could probably also do this in Python, but my knowledge of Python is nearly none.&lt;/p&gt;
&lt;h1 id=&#34;remote-interaction&#34;&gt;Remote interaction&lt;/h1&gt;
&lt;p&gt;You can probably make a guess as to how I set up the automation and interaction from other devices.
That&amp;rsquo;s right, I used an SSH forced command:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;no-pty,command=&amp;#34;/usr/local/sbin/pwr-switch toggle&amp;#34; ssh-ed25519 &amp;lt;contents of &amp;lt;lamp-key&amp;gt;.pub&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The unique thing here being that it needs to be executed as the root user in order to mess with the state of the pins.
(Or at least in the case of my setup.)
So having it be a forced command is a security benefit here as it prevents whatever device you&amp;rsquo;re using to toggle your lamp from having to log in as the root user.
All a device with the &lt;code&gt;&amp;lt;lamp-key&amp;gt;&lt;/code&gt; can do, is toggle the state of &lt;code&gt;GPIO 15&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You could contrivedly call this SIOT&amp;hellip;&lt;/p&gt;
&lt;p&gt;Since Android 12, there is the &amp;ldquo;Device controls&amp;rdquo; tile in the swipe-down-from-the-top-of-the-screen-menu.
Termux can interact with the API that this system provides and allows you to add buttons corresponding to Termux&amp;rsquo; shortcuts.
These shortcuts are executables found in &lt;code&gt;~/.shortcuts&lt;/code&gt; within the Termux environment.
Here I&amp;rsquo;ve created a little script that logs into my Raspberry Pi using the &lt;code&gt;&amp;lt;lamp-key&amp;gt;&lt;/code&gt;, allowing me to toggle my lamp at the tap of a button as long as I&amp;rsquo;m on my home network.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Hosting your own Git &#34;server&#34;</title>
      <link>/rambles/git-server/</link>
      <pubDate>Fri, 30 Sep 2022 14:27:31 +0200</pubDate>
      
      <guid>/rambles/git-server/</guid>
      <description>&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Pretty much the moment I started to work with Git a few years ago, I&amp;rsquo;ve wanted to host my own server.
I didn&amp;rsquo;t really bother looking into how that could work for a very long time.
I assumed it would be rather complex considering Git itself is an extremely complex (set of) tool(s) to work with.
I was hilariously wrong.
It&amp;rsquo;s &lt;em&gt;so&lt;/em&gt; simple to me that I&amp;rsquo;m under the impression that the lack of posts regarding the topic on blogs like this, is because it&amp;rsquo;s so simple.
Still, I&amp;rsquo;m going to spend the rest of this post explaining how to set up a server and why even calling a basic configuration a server, is a bit of an exaggeration.&lt;/p&gt;
&lt;h1 id=&#34;setting-up-the-server&#34;&gt;Setting up the server&lt;/h1&gt;
&lt;p&gt;The first step is to set up a Unix box of any kind.
Linux, any of the BSDs and probably even Darwin will work (hell, even Haiku might suffice).
The rest of this post assumes a Debian system (or rather, that you have the core GNUtils available).
Basics requirements are quite few:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It needs to be accessible using SSH.&lt;/li&gt;
&lt;li&gt;It needs Git installed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;adding-an-account&#34;&gt;Adding an account&lt;/h2&gt;
&lt;p&gt;Common practice dictates that you have a dedicated account for managing your Git repositories.
Common practice again dictates that this account be called &lt;code&gt;git&lt;/code&gt;.
Its home directory doesn&amp;rsquo;t really matter, but I like tossing it into &lt;code&gt;/srv/git&lt;/code&gt;.
Login shell also doesn&amp;rsquo;t matter &lt;em&gt;yet&lt;/em&gt;, I tend to change it to &lt;code&gt;bash&lt;/code&gt; for when I need to do things as the &lt;code&gt;git&lt;/code&gt; user.&lt;/p&gt;
&lt;p&gt;You can create an account with the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo useradd git -md /srv/git -s /bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; specifies where the home directory should be&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; creates the home directory&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; specifies what binary to use as login shell&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;setting-up-ssh&#34;&gt;Setting up SSH&lt;/h2&gt;
&lt;h3 id=&#34;client-side&#34;&gt;Client side&lt;/h3&gt;
&lt;p&gt;On the machine from where you want to push your git repositories, generate a new SSH key to access your Git server:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh-keygen -t ed25519 -f ~/.ssh/&amp;lt;git-key&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also recommend creating an entry in &lt;code&gt;~/.ssh/config&lt;/code&gt; for your Git server:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-ssh_config&#34; data-lang=&#34;ssh_config&#34;&gt;Host &amp;lt;host&amp;gt;-git
	Hostname &amp;lt;hostname&amp;gt;
	User git
	Identityfile ~/.ssh/&amp;lt;git-key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;server-side&#34;&gt;Server side&lt;/h3&gt;
&lt;p&gt;Next step is to make the &lt;code&gt;git&lt;/code&gt; account accessible over SSH.
&lt;code&gt;ssh-copy-id&lt;/code&gt; won&amp;rsquo;t work because the &lt;code&gt;git&lt;/code&gt; user doesn&amp;rsquo;t have a password.
So instead, log in as the &lt;code&gt;git&lt;/code&gt; user and create a &lt;code&gt;.ssh&lt;/code&gt; directory with an &lt;code&gt;authorized_keys&lt;/code&gt; file with the public half of the &lt;code&gt;&amp;lt;git-key&amp;gt;&lt;/code&gt; keypair:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo su - git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;umask&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;077&lt;/span&gt; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# strict read write permissions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir ~/.ssh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &amp;lt;git-key&amp;gt;.pub &amp;gt;&amp;gt; ~/.ssh/authorized_keys
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;adding-a-repository&#34;&gt;Adding a repository&lt;/h2&gt;
&lt;p&gt;You should now be able to log into your host as the &lt;code&gt;git&lt;/code&gt; user with using &lt;code&gt;&amp;lt;git-key&amp;gt;&lt;/code&gt;.
Setting up the route from client to server is half the work.&lt;/p&gt;
&lt;p&gt;Next step.
Make this actually serve Git repositories.
All this requires is a bare Git repository somewhere within &lt;code&gt;/srv/git&lt;/code&gt;.
To do this, log in as the &lt;code&gt;git&lt;/code&gt; user and run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git init --bare &amp;lt;repo-name&amp;gt;.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it.&lt;/p&gt;
&lt;p&gt;You now have a Git &amp;ldquo;server&amp;rdquo; with a repo named &lt;code&gt;&amp;lt;repo-name&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To add something to this repo, on your client machine create a new repository and add &lt;code&gt;&amp;lt;host&amp;gt;-git:/srv/git/&amp;lt;repo-name&amp;gt;.git&lt;/code&gt; as remote and push your project to it.
Common practice dictates that this remote be called &lt;code&gt;origin&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir my-fancy-project
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;cd&lt;/span&gt; my-fancy-project
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git init
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git remote add origin &amp;lt;host&amp;gt;-git:/srv/git/&amp;lt;repo-name&amp;gt;.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;# Self-hosted repo!&amp;#34;&lt;/span&gt; &amp;gt; README.md
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git add -A
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git commit -m &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;Initial commit&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git push -u origin main &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# assuming you use main as your default branch name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To clone this repository on another machine, add the &lt;code&gt;&amp;lt;git-key&amp;gt;&lt;/code&gt; SSH keypair and related configuration section in &lt;code&gt;~/.ssh/config&lt;/code&gt; to said machine and run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone &amp;lt;host&amp;gt;-git:/srv/git/&amp;lt;repo-name&amp;gt;.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;automation&#34;&gt;Automation&lt;/h1&gt;
&lt;p&gt;Creating bare repositories by hand gets annoying quite quickly.
I have an SSH forced command for another key that runs a script with the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8ec07c&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8ec07c&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BASELOC&lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;/srv/git&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;Enter new repo name:&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;read&lt;/span&gt; REPONAME
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;[&lt;/span&gt; -z $REPONAME &lt;span style=&#34;color:#fe8019&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;No repo initialised&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#fabd2f&#34;&gt;exit&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git init --bare $BASELOC/$REPONAME.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;authorized_keys&lt;/code&gt; entry for &lt;code&gt;git&lt;/code&gt; user:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-authorized_keys&#34; data-lang=&#34;authorized_keys&#34;&gt;command=&amp;#34;/srv/git/.bin/new-repo&amp;#34; ssh-ed25519 &amp;lt;new-repo-git-key&amp;gt;.pub
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Another thing you could do is change the login shell binary to a script that does something similar.
I haven&amp;rsquo;t bothered to do so for reasons that presently escape me.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>SSH Configuration</title>
      <link>/rambles/ssh/</link>
      <pubDate>Tue, 27 Sep 2022 11:40:31 +0200</pubDate>
      
      <guid>/rambles/ssh/</guid>
      <description>&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;If you&amp;rsquo;re anything like me, you&amp;rsquo;ll have at least a hand full of servers you&amp;rsquo;ll log into (at least) every now and then using SSH.
These servers don&amp;rsquo;t all have the same key.
And on top of that, I frequently have multiple keys per host.
Managing this by hand is a pain in the arse.
Thankfully there are a few tools that make it a breeze.
I will be going through what I have done to both my local configuration and what I tend to do with my server configuration.&lt;/p&gt;
&lt;h1 id=&#34;generating-keys&#34;&gt;Generating keys&lt;/h1&gt;
&lt;p&gt;In order to do anything with SSH in a secure way, you&amp;rsquo;ll need to make use of public and private keys.
These keypairs are generated using &lt;code&gt;ssh-keygen&lt;/code&gt;.
I typically generate mine using:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh-keygen -t ed25519 -f ~/.ssh/&amp;lt;new-key&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Without any parameters, it will generate an rsa3072 key.
This form of cryptography isn&amp;rsquo;t recommended as it&amp;rsquo;s become a bit flimsy with computers becoming stronger.
Instead I recommend at least adding the &lt;code&gt;-t ed25519&lt;/code&gt; flag to generate a ed25519 key.&lt;/p&gt;
&lt;p&gt;When prompted for a passphrase, &lt;strong&gt;&lt;em&gt;always&lt;/em&gt;&lt;/strong&gt; give it one.
The only situation where &lt;em&gt;not&lt;/em&gt; using a passphrase is acceptable is when you are planning on using the key for a &lt;a href=&#34;#forced-commands&#34;&gt;forced command&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;server-configuration&#34;&gt;Server Configuration&lt;/h1&gt;
&lt;p&gt;This is all done under the assumption that the you use the OpenSSH implementation on your server.
If you use something like Dropbear, I can&amp;rsquo;t help you as haven&amp;rsquo;t properly dug through it&amp;rsquo;s configuration file (yet).&lt;/p&gt;
&lt;p&gt;The things I see &lt;em&gt;way&lt;/em&gt; to often on the internet are&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;People not disabling password authentication.&lt;/li&gt;
&lt;li&gt;People not changing the default port.&lt;/li&gt;
&lt;li&gt;People not disabling root login and never using it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So lets go through these steps one by one.&lt;/p&gt;
&lt;h2 id=&#34;password-authentication&#34;&gt;Password Authentication&lt;/h2&gt;
&lt;p&gt;Password authentication is &lt;em&gt;the&lt;/em&gt; most basic thing every server should have disabled.
Otherwise, it is possible to brute force a connection into your server.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;But my server is not exposed to the internet.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I guess you &lt;em&gt;could&lt;/em&gt; get away with not disabling password authentication, but it&amp;rsquo;s still not a good idea in case, say, your network gets compromised.
On top of that, it&amp;rsquo;s less convenient to have to type in a password every time you want to log into your server (more in that in the SSH Agent section).&lt;/p&gt;
&lt;p&gt;In order to disable password authentication, open your SSH daemon configuration file: &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; and look for the following lines&amp;hellip;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-sshd_config&#34; data-lang=&#34;sshd_config&#34;&gt;...
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;hellip;uncomment &lt;code&gt;PasswordAuthentication&lt;/code&gt; and replace &amp;ldquo;yes&amp;rdquo; for &amp;ldquo;no&amp;rdquo;.
Make sure you still have a way into your server before restarting the daemon.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not planning on logging in as the root user, uncomment and set the following setting to &amp;ldquo;no&amp;rdquo;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-sshd_config&#34; data-lang=&#34;sshd_config&#34;&gt;...
#PermitRootLogin prohibit-password
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Be aware of the fact that you can still utilise the root account using &lt;code&gt;sudo su -&lt;/code&gt; (assuming you&amp;rsquo;re using &lt;code&gt;sudo&lt;/code&gt; on your server, else use whatever other privilege escalation tool you have at hand).&lt;/p&gt;
&lt;p&gt;Restarting the daemon on modern systems is usually done using:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl restart sshd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re not using systemd, I&amp;rsquo;m sure you know what command to use instead.&lt;/p&gt;
&lt;h2 id=&#34;adding-keys-to-authorized_keys&#34;&gt;Adding keys to &lt;code&gt;authorized_keys&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;When going through &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; you&amp;rsquo;ve probably come across a few lines resembling:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-sshd_config&#34; data-lang=&#34;sshd_config&#34;&gt;...
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile     .ssh/authorized_keys .ssh/authorized_keys2
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This means that the SSH daemon will check in &lt;code&gt;.ssh/authorized_keys&lt;/code&gt; in the home directory of the user as whom you&amp;rsquo;re trying to log in for authorized keys.
So the next step is to append your public key to this file in the home directory of the user as whom you want to be able to log in.
This can be done in a few ways.
The proper way is by using:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh-copy-id -i ~/.ssh/&amp;lt;key-file&amp;gt; &amp;lt;user&amp;gt;@&amp;lt;host&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m usually too lazy to remember there is a proper way and just open the file in &lt;code&gt;vi&lt;/code&gt; paste and it in there by hand during the same initial login when I&amp;rsquo;m disabling password authentication.
Either way works fine.&lt;/p&gt;
&lt;h2 id=&#34;changing-the-port&#34;&gt;Changing the port&lt;/h2&gt;
&lt;p&gt;The advantage to this is that your logs will be a lot cleaner if your host is exposed to the internet.
There are large amounts of bots hammering port &lt;code&gt;22&lt;/code&gt; on every IP address they can find with common usernames and passwords like &amp;ldquo;root&amp;rdquo; and &amp;ldquo;admin&amp;rdquo;.
A solution next to this is to use &lt;code&gt;fail2ban&lt;/code&gt; along side changing the port.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Won&amp;rsquo;t this mean I have to add the port to my login command every time I go to this server?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No, more in this in &lt;a href=&#34;#client-configuration&#34;&gt;the client configuration&lt;/a&gt; section&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; look for&amp;hellip;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-sshd_config&#34; data-lang=&#34;sshd_config&#34;&gt;...
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;hellip;and change the &lt;code&gt;Port&lt;/code&gt; to your liking, I tend to change this to something like 6969 or some other meme number.&lt;/p&gt;
&lt;p&gt;Another thing I tend to do is not open a port in my firewall, thus preventing any normal outside connections all together.
Instead opting to only connect over Yggdrasil and/or Tor.&lt;/p&gt;
&lt;h1 id=&#34;client-configuration&#34;&gt;Client configuration&lt;/h1&gt;
&lt;p&gt;If people tend not to think much about their server configuration, their client configuration is probably not even touched at all.&lt;/p&gt;
&lt;h2 id=&#34;the-sshconfig-file&#34;&gt;The &lt;code&gt;~/.ssh/config&lt;/code&gt; file&lt;/h2&gt;
&lt;p&gt;The very first thing I do after setting up a server, is add an entry to my &lt;code&gt;~/.ssh/config&lt;/code&gt; in order to manage its key, the user, the port and possibly subdomain should the need arise.&lt;/p&gt;
&lt;p&gt;A basic configuration section looks like the following:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-ssh_config&#34; data-lang=&#34;ssh_config&#34;&gt;Host &amp;lt;host&amp;gt; # this is something you can easily identify
	Host &amp;lt;hostname&amp;gt; # this does need to be an IP address or DNS record pointing to an IP address
	IdentityFile ~/.ssh/&amp;lt;key-file&amp;gt;
	User &amp;lt;user-name&amp;gt;
	Port &amp;lt;meme-number&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This allows you to log into host &lt;code&gt;&amp;lt;host&amp;gt;&lt;/code&gt; with on port &lt;code&gt;&amp;lt;meme-number&amp;gt;&lt;/code&gt; with key &lt;code&gt;~/.ssh/&amp;lt;key-file&amp;gt;&lt;/code&gt; as user &lt;code&gt;&amp;lt;user-name&amp;gt;&lt;/code&gt; without by typing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh &amp;lt;user-name&amp;gt;@&amp;lt;hostname&amp;gt; -p &amp;lt;meme-number&amp;gt; -i ~/.ssh/&amp;lt;key-file&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instead the following command will work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh &amp;lt;host&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;More information on the SSH config file can be found in the &lt;code&gt;ssh_config&lt;/code&gt; manpage.&lt;/p&gt;
&lt;p&gt;Some other frequently used settings for me are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AddKeysToAgent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IdentitiesOnly&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ProxyCommand&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;addkeystoagent&#34;&gt;&lt;code&gt;AddKeysToAgent&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Automatically adds the key to your SSH agent if you have one running.&lt;/p&gt;
&lt;p&gt;This is useful if you frequently log in and out of a certain host and don&amp;rsquo;t want to take the time to add it&amp;rsquo;s key to your agent manually.&lt;/p&gt;
&lt;h3 id=&#34;identitiesonly&#34;&gt;&lt;code&gt;IdentitiesOnly&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Ignore whatever keys your agent has and only use the contents of &lt;code&gt;IdentityFile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Useful for when you want to be able to log into the same host using multiple keys while using an SSH agent session.&lt;/p&gt;
&lt;h3 id=&#34;proxycommand&#34;&gt;&lt;code&gt;ProxyCommand&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Always connect to your host using a proxy, using a given command.&lt;/p&gt;
&lt;p&gt;Useful for when you can only access a host through a certain proxy.&lt;/p&gt;
&lt;p&gt;I use this for my Tor hosts:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-ssh_config&#34; data-lang=&#34;ssh_config&#34;&gt;Host tor-&amp;lt;host&amp;gt;
        Hostname &amp;lt;lengthy-56-character-string&amp;gt;.onion
	# this is dependent on the netcat implementation of the OpenBSD project, often packaged as &amp;#34;netcat-openbsd&amp;#34;
        ProxyCommand nc -X 5 -x localhost:9050 %h %p # this assumes you are running a tor proxy on your local system and attempts to make a connection through that
        Identityfile ~/.ssh/&amp;lt;key-file&amp;gt;
        User &amp;lt;user&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;the-ssh-agent&#34;&gt;The SSH Agent&lt;/h1&gt;
&lt;p&gt;If you&amp;rsquo;re using SSH keys with passphrases, it will very quickly get annoying to type in the passphrase every time you use a certain key.
To alleviate this tedium, the SSH agent exists.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using a full desktop environment, chances are that you already have an SSH agent running in the background.
You can check this by seeing if &lt;code&gt;$SSH_AGENT_PID&lt;/code&gt; is set to anything.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; $SSH_AGENT_PID
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If this isn&amp;rsquo;t set to anything, you can start an agent session by running:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;$(&lt;/span&gt;ssh-agent&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you can add keys to your agent with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh-add &amp;lt;/path/to/key-file&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also have it automatically drop keys after a specified amount of time with the &lt;code&gt;-t&lt;/code&gt; flag.
I tend to do this with my root keys as a security precaution.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh-add -t 1h ~/.ssh/&amp;lt;root-key&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Starting an SSH agent every time you open a new shell session gets quite annoying quite quickly.
There are a few things you can automate this.
The simplest is to add &lt;code&gt;eval $(ssh-agent)&lt;/code&gt; to your &lt;code&gt;~/.profile&lt;/code&gt;.
Another option, the one I prefer, is to use &lt;a href=&#34;https://www.funtoo.org/Funtoo:Keychain&#34;&gt;keychain&lt;/a&gt; from the Funtoo project.
It checks whether there&amp;rsquo;s an agent running every time you start a new login session.
If there is, it sets the SSH agent environment variables to the existing ones from some other session.
If there isn&amp;rsquo;t a running SSH session, it will start one.&lt;/p&gt;
&lt;p&gt;I have the following in my &lt;code&gt;~/.profile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;$(&lt;/span&gt;keychain --agents &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#39;gpg,ssh&amp;#39;&lt;/span&gt; --eval&lt;span style=&#34;color:#fe8019&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, it can also keep track of your GPG agent.&lt;/p&gt;
&lt;h1 id=&#34;forced-commands&#34;&gt;Forced Commands&lt;/h1&gt;
&lt;p&gt;Another amazing feature of SSH is forced commands.
The name is relatively self explanatory.
You give a public key the privilege to execute a single command and nothing else.
This is really useful if there is something that you frequently do on a server which is simple enough that it can be automated but still requires interaction from device.&lt;/p&gt;
&lt;p&gt;I make use of a forced command to open NCMPCPP on my MPD server.
Logging in every time and typing &lt;code&gt;ncmpcpp&lt;/code&gt; every time I wanted to add or remove some songs from the current playlist got annoying really fast.&lt;/p&gt;
&lt;p&gt;On my client machines I have an entry in my &lt;code&gt;~/.ssh/config&lt;/code&gt; with roughly the following:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-ssh_config&#34; data-lang=&#34;ssh_config&#34;&gt;Host &amp;lt;host&amp;gt;-radio
	Hostname &amp;lt;hostname&amp;gt;
	User &amp;lt;mpd-user&amp;gt;
	Port &amp;lt;meme-number&amp;gt;
	Identityfile ~/.ssh/&amp;lt;host&amp;gt;-radio
	IdentitiesOnly yes # here&amp;#39;s where forcing it to ignore the ssh agent comes in useful
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On my MPD server, I have the following in &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-authorized_keys&#34; data-lang=&#34;authorized_keys&#34;&gt;command=&amp;#34;ncmpcpp&amp;#34; ssh-ed25519 &amp;lt;contents of &amp;lt;host&amp;gt;-radio.pub&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When I &lt;code&gt;ssh&lt;/code&gt; to &lt;code&gt;&amp;lt;host&amp;gt;-radio&lt;/code&gt;, all I get is an NCMPCPP session.&lt;/p&gt;
&lt;p&gt;On one of my Raspberry Pis, I make use of a forced command to toggle my desk lamp using a little wrapper I wrote around the Pi&amp;rsquo;s GPIO interface.
It has the following line in &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-authorized_keys&#34; data-lang=&#34;authorized_keys&#34;&gt;no-pty,command=&amp;#34;/path/to/script/lamp toggle&amp;#34; ssh-ed25519 &amp;lt;contents of lamp-key.pub&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;no-pty&lt;/code&gt; option prevents any sessions opened with this key from starting an interactive shell session.&lt;/p&gt;
&lt;p&gt;Documentation of the &lt;code&gt;authorized_keys&lt;/code&gt; file can be found in the &lt;code&gt;sshd&lt;/code&gt; manpage under the &lt;code&gt;AUTHORIZED_KEYS FILE FORMAT&lt;/code&gt; section.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Nix Home Manager</title>
      <link>/rambles/nix-home-manager/</link>
      <pubDate>Mon, 19 Sep 2022 21:49:46 +0200</pubDate>
      
      <guid>/rambles/nix-home-manager/</guid>
      <description>&lt;h1 id=&#34;the-home-manager&#34;&gt;The Home Manager&lt;/h1&gt;
&lt;p&gt;The Nix Home Manager is a way to work with Nix in a declarative environment to manage your dotfiles and user environment packages.
This can be used on any system running the Nix packagemanager.
Personally, I&amp;rsquo;ve started to dabble around with it a bit after installing the Nix packagemanager in my Alpine installation.
Since I&amp;rsquo;ve already dabbled with Nix on a few systems through NixOS, I already knew the basics of functionally managing packages (or derivations) with the Nix packagemanager.
Hence I really quickly got sick of installing packages the imperative way.
After looking around for a bit, I found some post mentioning that managing packages in a functional environment outside of NixOS is a bit of a hack.
The post referred to some other sources, one of which used a custom meta package and another referred to the &lt;a href=&#34;https://nix-community.github.io/home-manager/&#34;&gt;Home Manager&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I had messed around with the Nix Home Manager a tiny bit before, but never &lt;em&gt;really&lt;/em&gt; gave it a chance to shine as I didn&amp;rsquo;t really understand it.
This time around, I decided to look up some tutorials and see how it worked.
When going through the instructions of either tutorial I used, I quickly came to the realisation why I had never &lt;em&gt;really&lt;/em&gt; looked at it.
Both tutorials took a lot of unnecessary steps according to the author&amp;rsquo;s will and assumed that everyone following their tutorials had the same preferences as them.
I obviously don&amp;rsquo;t.
So here&amp;rsquo;s my take on installing the Home Manager outside of NixOS.&lt;/p&gt;
&lt;h1 id=&#34;actually-using-home-manager&#34;&gt;Actually using Home Manager&lt;/h1&gt;
&lt;p&gt;Assuming you&amp;rsquo;re continuing from &lt;a href=&#34;/rambles/nix-on-other-distros-packagemanagers&#34;&gt;my previous article on Nix&lt;/a&gt;, the first step is to go to the Home Manager github page and go to the &lt;a href=&#34;https://nix-community.github.io/home-manager/index.html#sec-install-standalone&#34;&gt;page regarding the standalone installation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;From there, things will be quite self explanatory if you&amp;rsquo;re used to the (bare) basics of NixOS.
Though instead of using &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt; you&amp;rsquo;ll be using &lt;code&gt;$HOME/.config/nixpkgs/home.nix&lt;/code&gt; by default.
A basic Home Manager installation will leave you with a &lt;code&gt;home.nix&lt;/code&gt; file with the following content:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ config&lt;span style=&#34;color:#fe8019&#34;&gt;,&lt;/span&gt; pkgs&lt;span style=&#34;color:#fe8019&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt; }:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# Home Manager needs a bit of information about you and the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# paths it should manage.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  home&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;username &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;$USER&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  home&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;homeDirectory &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;/home/$USER&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# This value determines the Home Manager release that your&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# configuration is compatible with. This helps avoid breakage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# when a new Home Manager release introduces backwards&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# incompatible changes.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# You can update Home Manager without changing this value. See&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# the Home Manager release notes for a list of state version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# changes in each release.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  home&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;stateVersion &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;22.05&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# Let Home Manager install and manage itself.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  programs&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;home-manager&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After making any changes to your &lt;code&gt;home.nix&lt;/code&gt; file, you can apply them with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;home-manager switch
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you first want to see whether you build is going to be successful or not, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;home-manager build
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;installing-packages&#34;&gt;Installing packages&lt;/h2&gt;
&lt;p&gt;To add some packages, you&amp;rsquo;ll need to add them to the &lt;code&gt;home.packages&lt;/code&gt; array.
On my Alpine installation I have the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  home&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;packages &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;with&lt;/span&gt; pkgs; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    brave
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    vscodium
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice the &lt;code&gt;with pkgs;&lt;/code&gt; section.
This prevents you from having to add the &lt;code&gt;pkgs&lt;/code&gt; prefix to every package you want to add.
I don&amp;rsquo;t think this is the idiomatic way of adding packages to your configuration, but it allows me to be a bit lazier and it hasn&amp;rsquo;t caused any breakages yet.&lt;/p&gt;
&lt;h2 id=&#34;managing-dotfiles-and-configuration&#34;&gt;Managing dotfiles and configuration&lt;/h2&gt;
&lt;p&gt;Another amazing thing the Home Manager can do is manage your dotfiles.
And this in turn can be managed with Git.
More on this later.&lt;/p&gt;
&lt;h3 id=&#34;git-configuration&#34;&gt;Git configuration&lt;/h3&gt;
&lt;p&gt;For instance, I have it manage my Git config using the git module.
To do this, I have the something like the following in my &lt;code&gt;home.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  programs&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;git &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    enable &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ignores &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; [ &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;*.swp&amp;#34;&lt;/span&gt; ]; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# I don&amp;#39;t need to see that I still have a file open in vim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    signing &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      key &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;lt;gpg-fingerprint&amp;gt;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      signByDefault &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;false&lt;/span&gt;; &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# it would probably be better for security to have this be true, but doing so gets annoying really fast&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    userEmail &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;lt;user-email&amp;gt;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    userName &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;&amp;lt;user-name&amp;gt;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    extraConfig &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      init &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        defaultBranch &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s the &lt;a href=&#34;https://nix-community.github.io/home-manager/options.html#opt-programs.git.enable&#34;&gt;list of options&lt;/a&gt; supported by the git module.&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;strongly&lt;/em&gt; recommend digging through the documentation, looking for things that interest you in your current situation and setup.&lt;/p&gt;
&lt;h3 id=&#34;integrating-existing-dotfiles&#34;&gt;Integrating existing (dot)files&lt;/h3&gt;
&lt;p&gt;The Home Manager can also manage arbitrary (dot)files for you.
I have it link my &lt;code&gt;.zshrc&lt;/code&gt; into place with the following line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  home&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;file&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;.zshrc&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;source &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;./zshrc&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This looks for a file called &lt;code&gt;zshrc&lt;/code&gt; in the same directory as &lt;code&gt;home.nix&lt;/code&gt;.
From there, it symlinks it to &lt;code&gt;~/.zshrc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It can also manage recursive file structures.
I have it keep track of my &lt;code&gt;sxiv&lt;/code&gt; configuration with the following few lines:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  home&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;file&lt;span style=&#34;color:#fe8019&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#34;.config/sxiv&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    source &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b8bb26&#34;&gt;./sxiv&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    recursive &lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d3869b&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The interesting portion of this snippet is the &lt;code&gt;recursive&lt;/code&gt; boolean.
Because of this, Home Manager will recreate the directory structure found in &lt;code&gt;./sxiv&lt;/code&gt; in &lt;code&gt;~/.config/sxiv&lt;/code&gt; and symlinks the files found inside into place.&lt;/p&gt;
&lt;h1 id=&#34;git-integration&#34;&gt;Git integration&lt;/h1&gt;
&lt;p&gt;Since all the Home Manager requires is (at least) a single text file to manage your dotfiles and Nix environment packages, it&amp;rsquo;s really easy to keep track of your configuration using Git.
To that end, I have a bare repository on one of my home servers over at &lt;code&gt;/srv/git/nix/&amp;lt;nix-configuration&amp;gt;.git&lt;/code&gt;
As a remote, I have pointed my repo in &lt;code&gt;$HOME/.config/nixpkgs/&lt;/code&gt; to &lt;code&gt;&amp;lt;server-name&amp;gt;:/srv/git/nix/&amp;lt;nix-configuration&amp;gt;.git&lt;/code&gt;.
This works over ssh.
My &lt;code&gt;$HOME/.ssh/config&lt;/code&gt; contains the following lines to make the preceding work:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-ssh&#34; data-lang=&#34;ssh&#34;&gt;Host &amp;lt;server-name&amp;gt;
	Hostname &amp;lt;ip-address&amp;gt;
	User git
	Identityfile ~/.ssh/&amp;lt;private-key&amp;gt;
	Port 4242
	IdentitiesOnly yes # this makes using an ssh agent a bit easier when using multiple keys on the same host
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    
    <item>
      <title>Nix on Other Distros&#39; Packagemangers</title>
      <link>/rambles/nix-on-other-distros-packagemanagers/</link>
      <pubDate>Mon, 12 Sep 2022 11:37:11 +0200</pubDate>
      
      <guid>/rambles/nix-on-other-distros-packagemanagers/</guid>
      <description>&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;The Nix package manager is an amazing tool that allows you to manage your packages through a purely functional environment.
I&amp;rsquo;m not going to get into why it&amp;rsquo;s amazing or how it really works in this article.
This is purely a guide to installing it in Alpine and Debian Linux.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Why not use the official instructions?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The official instructions require you to &lt;code&gt;curl&lt;/code&gt; a script directly into &lt;code&gt;sh&lt;/code&gt;.
From there it requires sudo privileges to install the package manager itself.
This sets of a load of alarm bells in terms of security and what it&amp;rsquo;s going to do from there.
As the Nix package manager is packaged for both Debian and Alpine, my two favourite distros next to NixOS, there is no real reason &lt;em&gt;not&lt;/em&gt; to use their respective package managers.&lt;/p&gt;
&lt;p&gt;When you try to install Nix on Alpine using the aforementioned installation script you also get the warning that it only supports systemd and that you&amp;rsquo;re on your own when it comes to getting it to work on any other init system (Alpine uses OpenRC).
This problem is fixed in the Alpine package.&lt;/p&gt;
&lt;p&gt;Then there is also the benefit of of being able to remove it with either &lt;code&gt;apt autoremove --purge nix-setup-systemd&lt;/code&gt; or &lt;code&gt;apk del nix&lt;/code&gt; instead of having to run said same script a second time.&lt;/p&gt;
&lt;p&gt;Yes, I&amp;rsquo;m aware that you don&amp;rsquo;t &lt;em&gt;have&lt;/em&gt; to curl the script directly into &lt;code&gt;sh&lt;/code&gt; and that you can download it to your local system to see what it&amp;rsquo;s actually doing.
But that doesn&amp;rsquo;t take away from the fact that the official instructions tell you to perform an inherently insecure set of actions by trusting what is effectively a random script on the internet.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Doesn&amp;rsquo;t this mixing of packagemanagers cause a huge amount of anomalies?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No, that&amp;rsquo;s part of the beauty of Nix.
Pretty much everything it does lives in &lt;code&gt;/nix&lt;/code&gt; and is softlinked into place, meaning it never interferes with your existing package manager.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;em&gt;DISCLAIMER&lt;/em&gt;&lt;/em&gt;: Debian Stable at time of writing has Nix version &lt;code&gt;2.3.1&lt;/code&gt;, which appears to have some issues that would be fixed by moving to a later version.
Using the official instructions would sidestep this.&lt;/p&gt;
&lt;h1 id=&#34;installation-process&#34;&gt;Installation Process&lt;/h1&gt;
&lt;h2 id=&#34;package-installation&#34;&gt;Package Installation&lt;/h2&gt;
&lt;p&gt;The first step is to install the package itself.
On Debian this is done with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install nix
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On Alpine, you first have to add the &lt;code&gt;testing&lt;/code&gt; repo.
This is part of the &lt;code&gt;edge&lt;/code&gt; branch.
As far as I know, you &lt;em&gt;could in theory&lt;/em&gt; get away with just adding the &lt;code&gt;testing&lt;/code&gt; repo and not moving the rest of your system over to &lt;code&gt;edge&lt;/code&gt;, but I highly doubt that will do any good for the stability of your system.&lt;/p&gt;
&lt;p&gt;Moving your system over to the &lt;code&gt;edge&lt;/code&gt; branch is done by opening &lt;code&gt;/etc/apk/repositories&lt;/code&gt;, uncommenting the mirrors referring to &lt;code&gt;edge&lt;/code&gt; and commenting out the lines referring to (at time of writing) version &lt;code&gt;3.16&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From there, run&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doas apk -U upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip;to move your system over to &lt;code&gt;edge&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now installing Nix can be done as usual with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doas apk add nix
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will install the required binaries and the Nix daemon.&lt;/p&gt;
&lt;h2 id=&#34;starting-the-daemon&#34;&gt;Starting the Daemon&lt;/h2&gt;
&lt;p&gt;On Debian the Nix daemon is enabled by default.
To make sure it&amp;rsquo;s running and enabled, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl status nix-daemon.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If for whatever reason it&amp;rsquo;s not started and/or enabled, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl &lt;span style=&#34;color:#fabd2f&#34;&gt;enable&lt;/span&gt; --now nix-daemon.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On Alpine, the daemon isn&amp;rsquo;t added to any run level by default.
This is done using:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doas rc-update add nix-daemon
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Starting it is then done using:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doas rc-service nix-daemon start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;groups&#34;&gt;Groups&lt;/h2&gt;
&lt;p&gt;Next step is to add your account to the &lt;code&gt;nix-user&lt;/code&gt; or &lt;code&gt;nix&lt;/code&gt; group depending whether you are on Alpine or Debian respectively.&lt;/p&gt;
&lt;p&gt;On Debian this can be done with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo usermod -aG nix-user $USER
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And on Alpine this can be done with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doas addgroup $USER nix
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;environment-variables&#34;&gt;Environment variables&lt;/h2&gt;
&lt;p&gt;The next step is to set add the Nix binary dir to your &lt;code&gt;PATH&lt;/code&gt;.
To that end, I have the following in my &lt;code&gt;.profile&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;# nix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;export&lt;/span&gt; PATH&lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt;$PATH:$HOME/.nix-profile/bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now source your &lt;code&gt;.profile&lt;/code&gt; again, either using&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;source&lt;/span&gt; ~/.profile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip;or by logging out and back in again.&lt;/p&gt;
&lt;h2 id=&#34;adding-a-channel&#34;&gt;Adding a channel&lt;/h2&gt;
&lt;p&gt;Now you have a functioning Nix package manager configuration and all that remains to be done is adding and syncing the repo.&lt;/p&gt;
&lt;p&gt;The Alpine package defaults to adding the &lt;code&gt;unstable&lt;/code&gt; channel.
The Debian package doesn&amp;rsquo;t add any channels at all by default.
This can be verified with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nix-channel --list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To add the unstable channel to your channels, run the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nix-channel --add https://nixos.org/channels/nixpkgs-unstable
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can probably also add stable channels, but I haven&amp;rsquo;t tried that, as one of the reasons I want to use the Nix package manager on other distros than NixOS is for it&amp;rsquo;s newer packages.
(I am aware that the stable channel of NixOS is a lot newer than the Debian stable branch, which is precisely why I don&amp;rsquo;t want to to be my base system on machines where I have Debian installed.)&lt;/p&gt;
&lt;h2 id=&#34;syncing-channels&#34;&gt;Syncing channels&lt;/h2&gt;
&lt;p&gt;To sync your (just added) channel(s), run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nix-channel --update
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From this point on you can query your channel(s) using either &lt;a href=&#34;https://search.nixos.org/packages&#34;&gt;the website&lt;/a&gt; (which is a lot quicker) or:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nix-env -qa &amp;lt;query&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Packages can be imperatively installed using&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nix-env -iA nixpkgs.&amp;lt;package-name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip;and removed using&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nix-env --uninstall &amp;lt;package-name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Consult &lt;a href=&#34;https://nixos.org/manual/nix/stable/&#34;&gt;the manual&lt;/a&gt; for further usage.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Adblock</title>
      <link>/rambles/adblock/</link>
      <pubDate>Mon, 22 Aug 2022 23:46:09 +0200</pubDate>
      
      <guid>/rambles/adblock/</guid>
      <description>&lt;h3 id=&#34;ublock-origin&#34;&gt;UBlock Origin&lt;/h3&gt;
&lt;p&gt;Before I even get started, I&amp;rsquo;m going to tell you to use &lt;a href=&#34;https://ublockorigin.com/&#34;&gt;UBlock Origin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It is by far the most configurable and extensive adblocker that I know of.
I use it in every browser that supports it.&lt;/p&gt;
&lt;h1 id=&#34;moral-conundrums&#34;&gt;Moral Conundrums&lt;/h1&gt;
&lt;p&gt;You often hear people proclaim that blocking ads is bad for the internet the way that it is.
After which they will say that the alternative is to pay for every now-free aspect of the internet.
Usually through something like subscriptions.&lt;/p&gt;
&lt;p&gt;My response is to this is &amp;ldquo;Have you seen how popular crowd funding has gotten over the last few years?&amp;rdquo;
People already frequently pay for the content they want to consume.
Sure, it might be less than one might get through ad revenue, but that pays off in not having to shill to daddy {Google,Facebook,Apple,Amazon}.
This in turn means not indirectly violating your user&amp;rsquo;s privacy.&lt;/p&gt;
&lt;p&gt;But let&amp;rsquo;s analyse that a bit further.
The claim here is that the lack of advertisements would be bad, because it would mean large portions of the internet would become subscription based in some way.
For one, I&amp;rsquo;d argue that the presence of ads on the internet has done more harm than good, going as far as saying that, no, the internet would be better off without ads plastered everywhere.
This is never going to happen as there is, understandably a cooperate interest in the internet.
And two, not-insignificant portions of the internet &lt;em&gt;already are&lt;/em&gt; subscription based.&lt;/p&gt;
&lt;blockquote class=&#34;hyperbowl&#34;&gt;&#34;By blocking ads you are stealing from creators!&#34;&lt;/blockquote&gt;

&lt;p&gt;Sometimes you will even come across people who go as far to genuinely proclaim the preceding.
To those people, the only thing I can do is quote the classic &amp;ldquo;You wouldn&amp;rsquo;t download a car, would you?&amp;rdquo;
Shortly followed by saying &amp;ldquo;Yes I fucking would, given the opportunity&amp;rdquo;
No one owes you shit based on the amount of people have ignored the ads on your website.&lt;/p&gt;
&lt;p&gt;Then there is also the argument to be made that ads steal one&amp;rsquo;s attention.
The goal here being to manipulate you into buying a product.&lt;/p&gt;
&lt;p&gt;Much like with piracy, the you&amp;rsquo;re not missing out on anything.
The only way you would&amp;rsquo;ve seen any money from it, would be when you&amp;rsquo;re audience directly sees your content and happens to get an ad shoved in their face.
Though I suppose in the case of ads, your audience has no choice but to support you when they don&amp;rsquo;t use an adblocker.
In other words, you are forcing your audience to sacrifice their a part attention to support you, whether they want to or not.
In my opinion, this makes it morally wrong to make money off of ads.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d argue it is a moral imperative to use an adblocker.&lt;/p&gt;
&lt;p&gt;Then there is also the angle of corporations focussing on ads more and more.
This in turn means that avoiding an absurd portion of cooperate influence has become hilariously easy;
Just install an adblocker that isn&amp;rsquo;t sponsored by an ad company.
The thing is that most people are too lazy to install an adblocker and thus ads are still a viable business model.&lt;/p&gt;
&lt;p&gt;Subscription services such as the one that started as a DVD and VHS rental business and the other one with a monopoly over a significant portion of pop culture, have been working towards ad-supported tiers while drastically increasing the price of their paid tiers.
It would be pretty funny if these ads could be avoided using UBlock Origin.
Personally, I prefer using MPV wherever possible, so I probably won&amp;rsquo;t find out how well that might work.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Hugo</title>
      <link>/rambles/hugo/</link>
      <pubDate>Thu, 18 Aug 2022 14:53:00 +0200</pubDate>
      
      <guid>/rambles/hugo/</guid>
      <description>&lt;h1 id=&#34;reflection&#34;&gt;Reflection&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;ve tried to take a look at &lt;a href=&#34;https://gohugo.io&#34;&gt;Hugo&lt;/a&gt; for a few times before properly diving into it.&lt;/p&gt;
&lt;p&gt;The first time was back when I first decided to look into making a website not-completely by hand.
I had hacked a few previous iterations of this site together and was happy with the design.
The next step was to write some blobs of text for people to read besides the random antics that can be found in the side bar.&lt;/p&gt;
&lt;p&gt;A few problems arose here.
For one, writing directly in HTML is a pain.
So I decided to write in markdown and convert that to HTML using &lt;a href=&#34;https://pandoc.org&#34;&gt;Pandoc&lt;/a&gt;.
From there, I still had to index every page completely by hand.
The prospect of this annoyed me quite a bit, so I decided to take a cursory glance at Hugo.&lt;/p&gt;
&lt;p&gt;The quick start guide showed how to take a pre-existing theme, a bunch of markdown files and turn that into website.
Never having been one to use other people&amp;rsquo;s work as-is, I quickly gave up when I saw the structure of the themes and couldn&amp;rsquo;t be bothered to give it a proper shot.
This also gave me the impression of it being a Wordpress-esque environment that works great as long as you stick within the standards.&lt;/p&gt;
&lt;p&gt;A bit later I found out that Pandoc supports templates.
So I tried my hand at hacking a site generator together based on a Makefile and Pandoc.
This worked&amp;hellip; somewhat.
But I deemed it more trouble than it was worth and never got very far with it.&lt;/p&gt;
&lt;p&gt;A few weeks ago, I came across someone mentioning Hugo again and how it was really great.
I decided to give it another shot.
This time really diving into the structure of the themes and it clicked.
A thing that probably helped this time around was that it very quickly became clear to me that the features I had been half arsedly implementing in my Makefile were standard features for Hugo.
Another thing that undoubtedly helped being that the philosophy and syntax of Pandoc&amp;rsquo;s more advanced features are quite similar to Hugo&amp;rsquo;s.&lt;/p&gt;
&lt;h2 id=&#34;disservice-to-hugo&#34;&gt;Disservice to Hugo&lt;/h2&gt;
&lt;p&gt;One big thing I bump into with Hugo is the fact that most Hugo websites I come across take one template and &lt;em&gt;maybe&lt;/em&gt; change the colorscheme.
I feel this is a great disservice to the potential that Hugo has to offer in terms of flexibility.
Yes, you &lt;em&gt;can&lt;/em&gt; have it act similar to Wordpress, but you don&amp;rsquo;t &lt;em&gt;have to&lt;/em&gt;.
I was scared off because I assumed would have to use some existing template or get my CSS to work within a Hugo context.
The process of which, I assumed, would be mostly having beat Hugo into submission before it would display the things I wanted in the way I wanted.&lt;/p&gt;
&lt;p&gt;The beauty of Hugo and ultimately the reason this is now a Hugo site, is it&amp;rsquo;s flexibility.
You wouldn&amp;rsquo;t be able to tell this is a Hugo site if you don&amp;rsquo;t dig through the metadata fields in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag.
And I guess that is also kind of the problem with it.
Most people visibly using Hugo take some standard template proudly proclaiming that the page we&amp;rsquo;re presently looking at is generated using it.&lt;/p&gt;
&lt;p&gt;And the people who want to use Hugo but don&amp;rsquo;t care for the pre-existing themes, don&amp;rsquo;t care to proudly shout to the world that their site is made with it.
This is why I got the impressions of Hugo that I did.&lt;/p&gt;
&lt;p&gt;In that sense, I&amp;rsquo;m part of the problem in not showing that Hugo can do pretty much anything you can think of in the realm of static, somewhat blog oriented websites.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Aural Insanity</title>
      <link>/insanity/</link>
      <pubDate>Wed, 10 Aug 2022 15:09:31 +0200</pubDate>
      
      <guid>/insanity/</guid>
      <description>&lt;h1 id=&#34;bid-farewel-to-your-sanity&#34;&gt;Bid Farewel to your Sanity&lt;/h1&gt;
&lt;h2 id=&#34;a-thing-consisting-of-4-audio-tracks&#34;&gt;A thing consisting of 4 audio tracks.&lt;/h2&gt;
&lt;p&gt;The tracks used in this&amp;hellip; thing are from the following games:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Track Source&lt;/th&gt;
          &lt;th&gt;Channel&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Don&#39;t Starve OST - Ragtime&lt;/td&gt;
          &lt;td&gt;Center&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Blood - The Chanting track&lt;/td&gt;
          &lt;td&gt;Center&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Painkiller - The Carnival level&lt;/td&gt;
          &lt;td&gt;Left&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Blood - The Mall/Elevator music&lt;/td&gt;
          &lt;td&gt;Right&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This is a file dedicated to aural insanity produced every now and then&lt;/p&gt;
&lt;audio controls=&#34;true&#34;&gt;
	&lt;source src=&#34;/audio/insanity.wav&#34; type=&#34;audio/wav&#34;&gt;
	Sorry mate, your browser doesn&#39;t support playing audio files.
	&lt;/source&gt;
&lt;/audio&gt;


&lt;h1 id=&#34;anvil&#34;&gt;Anvil&lt;/h1&gt;
&lt;p&gt;This is the result of deciding to mess around with LMMS, a distorted Minecraft anvil sound ripped from YouTube and having a friend nearby with knowledge on how to create music (in other words, a musician).&lt;/p&gt;
&lt;p&gt;I made an anvil melody of sorts and Vlams added a drum sample loop and a few synthesizers.&lt;/p&gt;
&lt;audio controls=&#34;true&#34;&gt;
	&lt;source src=&#34;/audio/aaaaanvil.flac&#34; type=&#34;audio/flac&#34;&gt;
	Sorry mate, your browser doesn&#39;t support playing audio files.
	&lt;/source&gt;
&lt;/audio&gt;


&lt;h1 id=&#34;orca&#34;&gt;Orca&lt;/h1&gt;
&lt;p&gt;Some &lt;a href=&#34;/rambles/orca/&#34;&gt;Orca experiments.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;plinkinator&#34;&gt;plinkinator&lt;/h2&gt;
&lt;details&gt;
	&lt;summary&gt;
		Orca source
	&lt;/summary&gt;

&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-orca&#34; data-lang=&#34;orca&#34;&gt;..................
..nVC.............
..................
5U9..Vn..4U9..Vn..
.*:04C....*:03C...
..................
3U5..Vn...........
..:05C............
..................
3U8..Vn...........
.*:06C............
..................
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;

&lt;h3 id=&#34;first-result&#34;&gt;First result&lt;/h3&gt;
&lt;audio controls=&#34;true&#34;&gt;
	&lt;source src=&#34;/audio/orca/plinkinator.flac&#34; type=&#34;audio/flac&#34;&gt;
	Sorry mate, your browser doesn&#39;t support playing audio files.
	&lt;/source&gt;
&lt;/audio&gt;


&lt;h3 id=&#34;later-variant&#34;&gt;Later variant&lt;/h3&gt;
&lt;audio controls=&#34;true&#34;&gt;
	&lt;source src=&#34;/audio/orca/varied_plinkinator.flac&#34; type=&#34;audio/flac&#34;&gt;
	Sorry mate, your browser doesn&#39;t support playing audio files.
	&lt;/source&gt;
&lt;/audio&gt;


&lt;h2 id=&#34;shepard-tone&#34;&gt;Shepard tone&lt;/h2&gt;
&lt;details&gt;
	&lt;summary&gt;
		Orca source
	&lt;/summary&gt;

&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-orca&#34; data-lang=&#34;orca&#34;&gt;.C8C7........
.1.67TABCDEFG
.J.3XG.......
.18T1234567..
...2.........
D1.J.........
*:02G.2......
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;

&lt;h3 id=&#34;climb&#34;&gt;Climb&lt;/h3&gt;
&lt;audio controls=&#34;true&#34;&gt;
	&lt;source src=&#34;/audio/orca/climb.flac&#34; type=&#34;audio/flac&#34;&gt;
	Sorry mate, your browser doesn&#39;t support playing audio files.
	&lt;/source&gt;
&lt;/audio&gt;


&lt;h3 id=&#34;fall&#34;&gt;Fall&lt;/h3&gt;
&lt;p&gt;Same as &amp;lsquo;climb&amp;rsquo; but with the note and octave loops reversed.
&lt;audio controls=&#34;true&#34;&gt;
	&lt;source src=&#34;/audio/orca/fall.flac&#34; type=&#34;audio/flac&#34;&gt;
	Sorry mate, your browser doesn&#39;t support playing audio files.
	&lt;/source&gt;
&lt;/audio&gt;

&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Browsers</title>
      <link>/rambles/browsers/</link>
      <pubDate>Mon, 04 Apr 2022 02:54:33 +0200</pubDate>
      
      <guid>/rambles/browsers/</guid>
      <description>&lt;h1 id=&#34;web-browsers-with-vim-bindings&#34;&gt;Web Browsers With Vim Bindings&lt;/h1&gt;
&lt;p&gt;If there&amp;rsquo;s one thing I like it&amp;rsquo;s Vim bindings everywhere.
Since all Vim browser extentions suck on some level, the remaining choice I have is to use browser with built in vim bindings.
To that end, there are technically a few options.&lt;/p&gt;
&lt;p&gt;Those being:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://qutebrowser.org&#34;&gt;Qutebrowser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://vieb.dev&#34;&gt;Vieb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://fanglingsu.github.io/vimb&#34;&gt;Vimb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nyxt.atlas.engineer&#34;&gt;Nyxt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These projects are great but all have their problems.
Let&amp;rsquo;s go through them bottom-to-top.&lt;/p&gt;
&lt;h2 id=&#34;nyxt&#34;&gt;Nyxt&lt;/h2&gt;
&lt;p&gt;Nyxt is written in Common Lisp, making it very easy to hack on.
Supports either QtWebEngine or WebKitGTK.
It also appeals more to the Emacs world then the Vim world.
Much like Emacs, Nyxt &lt;em&gt;does&lt;/em&gt; have the option of Vim bindings, but they feel somewhat half baked.
Then there is the problem of what little interface there is not being particularly clear.
To be fair, I haven&amp;rsquo;t really given it a proper shot because it&amp;rsquo;s configured on Common fucking Lisp.
Not being much of an Emacs user, I have little to no interest in learning Lisp to configure a browser.&lt;/p&gt;
&lt;h2 id=&#34;vimb&#34;&gt;Vimb&lt;/h2&gt;
&lt;p&gt;The suckless option.&lt;/p&gt;
&lt;p&gt;Uses WebKitGTK.&lt;br&gt;
Is written in C and configured in a vimscript-esque syntax.
The thing that turns me off from this browser is it being &lt;em&gt;too&lt;/em&gt; suckless.
It almost feels like surf with a slightly more accessible way of configuring it through something that &lt;em&gt;isn&amp;rsquo;t&lt;/em&gt; a header file.&lt;/p&gt;
&lt;p&gt;Practical reasons that prevent me from using it are the lack of proper ad blocking and tabs.
By default, it also uses the number keys for URL hinting instead of the home row.
It also has similar performance to suckless&amp;rsquo; surf
In other words, it takes quite a long time to load pages, especially if they contain a large amount of JavaScript (though you shouldn&amp;rsquo;t be visiting those pages unless strictly necessary) and rather quickly hogs quite a lot of resources.&lt;/p&gt;
&lt;h2 id=&#34;vieb&#34;&gt;Vieb&lt;/h2&gt;
&lt;p&gt;An Electron based browser.&lt;/p&gt;
&lt;p&gt;Say whatever you want about Vimb&amp;rsquo;s performance, but Vieb makes Google Chrome seem like a well balanced product.
I&amp;rsquo;ve seen it eat 25% of a CPU thread with a single tab containing nothing but the Vieb documentation.&lt;/p&gt;
&lt;p&gt;It has a rather pretty interface and could (if the github page is to be believed) be used to interact with other Electron applications like the Discord client as if it were ran natively (don&amp;rsquo;t quote me on that, I&amp;rsquo;m too lazy to check and probably wrong).&lt;/p&gt;
&lt;h2 id=&#34;qutebrowser&#34;&gt;Qutebrowser&lt;/h2&gt;
&lt;p&gt;Which brings us here.&lt;br&gt;
Qutebrowser is written and configured in Python; and uses the QtWebEngine.
It&amp;rsquo;s extremely flexible and easy to configure.
It has reasonable ad blocking that allows for the addition of blocklists in a plain text file.
A problem I have with it are that I can&amp;rsquo;t choose which JavaScript elements to block and which to allow, like UMatrix.
But then I did see plans to add support for Firefox extensions which would solve this problem.
Another minor gripe I have is that scrolling through long pages can look a little sluggish.&lt;/p&gt;
&lt;p&gt;With these changes and (if it weren&amp;rsquo;t a gigantic nightmare) Gecko support, it would be the perfect browser for me.&lt;/p&gt;
&lt;h1 id=&#34;other-web-browsers&#34;&gt;Other Web Browsers&lt;/h1&gt;
&lt;p&gt;When I need to use a site that requires some JS, but still functions without enabling everything, my choice of browser is either Librewolf or a heavily configured Firefox.&lt;/p&gt;
&lt;p&gt;From there I use the following list of extensions to make the web usable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ueokande/vim-vixen&#34;&gt;vim-vixen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gorhill/uBlock&#34;&gt;uBlockOrigin&lt;/a&gt; (Installed by default on Librewolf)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/einaregilsson/Redirector&#34;&gt;redirector&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tosdr/browser-extensions&#34;&gt;ToS;DR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Vim</title>
      <link>/rambles/vim/</link>
      <pubDate>Mon, 21 Mar 2022 01:17:06 +0200</pubDate>
      
      <guid>/rambles/vim/</guid>
      <description>&lt;h1 id=&#34;vim-cheat-sheet&#34;&gt;Vim Cheat sheet&lt;/h1&gt;
&lt;p&gt;This is a little Vim cheat sheet with thing people generally don&amp;rsquo;t seem to be particularly familiar with when it comes to Vim.
This is about Vim, not NeoVim, but I most things with still apply to NeoVim.&lt;/p&gt;
&lt;h2 id=&#34;self-explanatory-things&#34;&gt;Self-explanatory things&lt;/h2&gt;
&lt;p&gt;These are a few bindings that I don&amp;rsquo;t feel require an extensive explanation.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;binding&lt;/th&gt;
          &lt;th&gt;action&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Z Z&lt;/td&gt;
          &lt;td&gt;write and quit; equivalent to &lt;code&gt;:wq&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Z Q&lt;/td&gt;
          &lt;td&gt;quit; equivalent to &lt;code&gt;:q!&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;:x&lt;/td&gt;
          &lt;td&gt;write and quit; equivalent to &lt;code&gt;:wq&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;g u&lt;/td&gt;
          &lt;td&gt;swap characters to lower case&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;g u u&lt;/td&gt;
          &lt;td&gt;swap characters to lower case on current line&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;g U&lt;/td&gt;
          &lt;td&gt;swap characters to upper case&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;g U U&lt;/td&gt;
          &lt;td&gt;swap characters to upper case on current line&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;g {j,k}&lt;/td&gt;
          &lt;td&gt;if the current line you&amp;rsquo;re on spans more then the width of your screen, go down to the portion that&amp;rsquo;s past the linebreak&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;~&lt;/td&gt;
          &lt;td&gt;toggle case&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;z g&lt;/td&gt;
          &lt;td&gt;add word to current dictionary&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;[ s&lt;/td&gt;
          &lt;td&gt;highlight previous misspelled word&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;] s&lt;/td&gt;
          &lt;td&gt;highlight next misspelled word&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;z =&lt;/td&gt;
          &lt;td&gt;open spelling suggestions based on current dictionary and highlighted word&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;.&lt;/td&gt;
          &lt;td&gt;repeat last modify operation&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;;&lt;/td&gt;
          &lt;td&gt;repeat last move operation&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;!&lt;/td&gt;
          &lt;td&gt;start command with &lt;code&gt;:&amp;lt;selection&amp;gt;!&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;splits-and-terminals&#34;&gt;Splits and Terminals&lt;/h2&gt;
&lt;p&gt;You can split your vim window with somewhat Emacs-like chords by default; I don&amp;rsquo;t bother changing them because I use with quite a few different computers, not all of which have my Vim dotfiles installed.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;binding&lt;/th&gt;
          &lt;th&gt;action&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;C-w s&lt;/td&gt;
          &lt;td&gt;Horizontal split&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;C-w v&lt;/td&gt;
          &lt;td&gt;Vertical split&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;C-w {h,j,k,l}&lt;/td&gt;
          &lt;td&gt;Move focus to split {left,down,up,right}&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;C-w S-{h,j,k,l}&lt;/td&gt;
          &lt;td&gt;Move split to {left,down,up,right}&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Another usefull thing I don&amp;rsquo;t see a lot of people do is open a terminal session in vim.
This can be really quite useful if you quickly need to change or check something.
You do this with the &lt;code&gt;:terminal&lt;/code&gt; command.
In Vim, this will horizontally split your current window and open a terminal session in the top half.
(Yes, you can also open Vim sessions in these terminal sessions if you feel like it).
You can navigate to and from it just like any other splits.
In NeoVim terminals are handled significantly worse and is the main reason I went back to base Vim.&lt;/p&gt;
&lt;h2 id=&#34;tips&#34;&gt;Tips&lt;/h2&gt;
&lt;p&gt;Something I came across some time ago is that you can interpet the current line with whatever you want using&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;:.!&amp;lt;interpeter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So for instance running&amp;hellip;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;:.!bash
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;hellip;while highlighting the line&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fabd2f&#34;&gt;echo&lt;/span&gt; Line&lt;span style=&#34;color:#fe8019&#34;&gt;{&lt;/span&gt;1..5&lt;span style=&#34;color:#fe8019&#34;&gt;}&lt;/span&gt; | sed &lt;span style=&#34;color:#b8bb26&#34;&gt;&amp;#39;s/ /\n/g&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip;will result in:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Line1
Line2
Line3
Line4
Line5
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;configuration&#34;&gt;Configuration&lt;/h1&gt;
&lt;p&gt;Some settings I like putting in my git configuration files.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-vimrc&#34; data-lang=&#34;vimrc&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; nocompatible
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; termguicolors
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; cursorline
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; hlsearch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; ignorecase
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; smartcase
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; number
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; relativenumber
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; wildmenu
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; mouse=
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; scrolloff=&lt;span style=&#34;color:#d3869b&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; listchars=tab:│\ ,lead:·,trail:·,eol:¬ &lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;&amp;#34;&amp;#39;lead&amp;#39; is a NeoVim specific option&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;set&lt;/span&gt; list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#928374;font-style:italic&#34;&gt;&amp;#34; I haven&amp;#39;t tried if this works in base vim.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;match ExtraWhitespace &lt;span style=&#34;color:#b8bb26&#34;&gt;/\s\+$/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fe8019&#34;&gt;highlight&lt;/span&gt; ExtraWhitespace guifg=red
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>About</title>
      <link>/about/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/about/</guid>
      <description>&lt;h1 id=&#34;HUMANOID&#34;&gt;The HUMANOID running this thing&lt;/h1&gt;
&lt;h2 id=&#34;identity---s-a-funny-thing-isnt-it&#34;&gt;Identity - &amp;rsquo;s a funny thing isn&amp;rsquo;t it?&lt;/h2&gt;
&lt;div class=&#34;about&#34;&gt;
&lt;a title=&#34;Vector graphic&#34; href=&#34;/logoOptimised.svg&#34;&gt;&lt;img src=&#34;/logoOptimised.png&#34; /&gt;&lt;/a&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;b&gt;Name:&lt;/b&gt; Marty&lt;/li&gt;
	&lt;li title=&#34;13-6-2001 Gregorian calendar&#34;&gt;&lt;b&gt;Date of birth:&lt;/b&gt; 18-con-3167&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;Gender:&lt;/b&gt; Not really&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;Email:&lt;/b&gt; &lt;a href=&#34;mailto:marty.wanderer@disroot.org&#34;&gt;marty.wanderer@disroot.org&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;&lt;a href=&#34;/keys/gpg.asc&#34;&gt;GPG key&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;Country:&lt;/b&gt; Check the TLD&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;&lt;a href=&#34;gemini://voidcruiser.nl&#34;&gt;Gemini&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;&lt;a href=&#34;https://gitlab.com/EternalWanderer&#34;&gt;Gitlab&lt;/a&gt;&lt;/b&gt; - because I evidently can&#39;t be arsed to host my own git interface yet...&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;&lt;a rel=&#34;me&#34; href=&#34;https://tech.lgbt/@nuclearegg&#34;&gt;Mastodon&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;h1 id=&#34;the-site-itself&#34;&gt;The site itself&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Colorscheme: &lt;a href=&#34;https://github.com/morhetz/gruvbox&#34;&gt;Gruvbox&lt;/a&gt;
Depending on &lt;code&gt;prefers-color-scheme:&lt;/code&gt; in your browser settings being &lt;code&gt;light&lt;/code&gt; or not, you get to see the light variant or not.&lt;/li&gt;
&lt;li&gt;This site is viewable and usable on every browser I&amp;rsquo;ve thrown at it so far.&lt;br&gt;
I even spent a 10 minutes making this site look reasonable on mobile devices.&lt;br&gt;
Here&amp;rsquo;s the browser list:
&lt;ul&gt;
&lt;li&gt;Qutebrowser&lt;/li&gt;
&lt;li&gt;Bromite&lt;/li&gt;
&lt;li&gt;LibreWolf&lt;/li&gt;
&lt;li&gt;FireFox&lt;/li&gt;
&lt;li&gt;UnGoogled Chromium&lt;/li&gt;
&lt;li&gt;Lynx&lt;/li&gt;
&lt;li&gt;Midori&lt;/li&gt;
&lt;li&gt;w3m&lt;/li&gt;
&lt;li&gt;Dillo&lt;/li&gt;
&lt;li&gt;Netsurf&lt;/li&gt;
&lt;li&gt;Nyxt&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;software-used-by-humanoid&#34;&gt;Software used by &lt;a href=&#34;#HUMANOID&#34;&gt;$HUMANOID&lt;/a&gt;&lt;/h1&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;category&lt;/th&gt;
          &lt;th&gt;programs&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Operating system:&lt;/td&gt;
          &lt;td&gt;NixOS, Debian, Alpine&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Window manager:&lt;/td&gt;
          &lt;td&gt;XMonad&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Graphical browser:&lt;/td&gt;
          &lt;td&gt;LibreWolf, UnGoogled Chromium, Qutebrowser&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Text browser:&lt;/td&gt;
          &lt;td&gt;Lynx, w3m&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Gemini client:&lt;/td&gt;
          &lt;td&gt;Lagrange, Amfora&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Terminal:&lt;/td&gt;
          &lt;td&gt;Kitty&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Text editors:&lt;/td&gt;
          &lt;td&gt;Vim, NeoVim, VSCodium with NVim plugin&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Image viewer:&lt;/td&gt;
          &lt;td&gt;nsxiv&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Video player:&lt;/td&gt;
          &lt;td&gt;mpv&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Music player:&lt;/td&gt;
          &lt;td&gt;mpd + ncmpcpp&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</description>
    </item>
    
    <item>
      <title>Cheatsheet</title>
      <link>/cheatsheet/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/cheatsheet/</guid>
      <description>&lt;h1 id=&#34;cheatsheet&#34;&gt;Cheatsheet&lt;/h1&gt;
&lt;p&gt;This is a collection of random commands that I want store somewhere I wont forget it&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&#34;zfs&#34;&gt;ZFS&lt;/h2&gt;
&lt;p&gt;The ZFS settings you probably want when creating a pool. Shamelessly ripped from &lt;a href=&#34;https://jrs-s.net/2018/08/17/zfs-tuning-cheat-sheet/&#34;&gt;another cheatsheet&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo zpool create gayms mirror /dev/sda /dev/sdb -O compression&lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt;lz4 -o ashift&lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#d3869b&#34;&gt;12&lt;/span&gt; -O atime&lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt;off -O xattr&lt;span style=&#34;color:#fe8019&#34;&gt;=&lt;/span&gt;sa
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;firefox-quirks&#34;&gt;Firefox quirks&lt;/h2&gt;
&lt;p&gt;Re-enable the protocol indicator in the URL bar in Firefox by setting the &lt;code&gt;browser.urlbar.trimURLs&lt;/code&gt; flag to false.&lt;/p&gt;
&lt;h2 id=&#34;headscale&#34;&gt;Headscale&lt;/h2&gt;
&lt;p&gt;Creating a user from the CLI&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;headscale user create &amp;lt;username&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;headscale 
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;random-shell-stuff&#34;&gt;Random shell stuff&lt;/h2&gt;
&lt;p&gt;Redirect stderr to stdout&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;the-rsync-flags-youll-want-to-use&#34;&gt;The &lt;code&gt;rsync&lt;/code&gt; flags you&amp;rsquo;ll want to use&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;rsync -avPz
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;For some reason I wouldn&amp;rsquo;t be able to get myself to keep track of a &lt;code&gt;notes.md&lt;/code&gt; file if my life depended on it.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Services</title>
      <link>/services/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/services/</guid>
      <description>&lt;p&gt;These are a few serices I provide to the people who may be interested in them.&lt;/p&gt;
&lt;h1 id=&#34;searxng-instance&#34;&gt;&lt;a href=&#34;/searx&#34;&gt;SearXNG instance&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Since DuckDuckGo decided to censor content a few weeks ago at time of writing, the thought of spinning up another SearX instance started to form in the back of my mind.
Then &lt;em&gt;at&lt;/em&gt; time of writing, they decided to start to block more content in relation to copyright infringing material.
This still doesn&amp;rsquo;t nessecarily mean too much, but who knows how much they&amp;rsquo;re going to continue blocking now they&amp;rsquo;ve started in the first place.&lt;/p&gt;
&lt;p&gt;So here&amp;rsquo;s that SearX instance, &lt;b class=&#34;gay&#34;&gt;enjoy!&lt;/b&gt;
&lt;/p&gt;
&lt;p&gt;I have got to say that the theming of SearXNG has improved quite a lot either over the years or in my mind.
At the very least I think the default theme looks quite nice these days.&lt;/p&gt;
&lt;noscript&gt;
&lt;hr /&gt;
&lt;p class=&#34;gay&#34;&gt;SearXNG does make use of JavaScript for certain functions, but it&amp;#39;s purely to make using it a smoother experiece and it&amp;#39;s perfectly functional without JavaScript.&lt;/p&gt;
&lt;/noscript&gt;

</description>
    </item>
    
  </channel>
</rss>
