<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>blog</title>
    <link>https://evilcookie.de</link>
    <description>Hi, I&#39;m Raphael by day and evilcookie by night.&lt;/br&gt;&lt;/br&gt;I&#39;m a neurodivergent software developer from germany and write about my computer journey. I like linux, love c and do &lt;a href=&#39;go-concepts.html&#39;&gt;go&lt;/a&gt; for a living. You can find my code on &lt;a href=&#39;https://github.com/RaphaelPour/&#39;&gt;github&lt;/a&gt;. Sometimes I &lt;a href=&#39;cinema-visits.html&#39;&gt;visit the cinema&lt;/a&gt;, &lt;a href=&#39;til---today-i-learned.html &#39;&gt;learn things&lt;/a&gt;, &lt;a href=&#39;magic-numbers.html&#39;&gt;collect magic numbers&lt;/a&gt;, &lt;a href=&#39;tila---today-i-laughed-about.html&#39;&gt;laugh about nerdy jokes&lt;/a&gt; or &lt;a href=&#39;https://soundcloud.com/noise-taeter&#39;&gt;make some music&lt;/a&gt;.</description>
    <managingEditor> (Raphael Pour)</managingEditor>
    <pubDate>Tue, 03 Feb 2026 12:11:12 +0100</pubDate>
    <item>
      <title>Design audio PCBs with KiCad</title>
      <link>https://evilcookie.de/design-audio-pcbs-with-kicad.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Design audio PCBs with KiCad</h1>

<p><img src="design-audio-pcbs-with-kicad_kicad.jpg"/></p>

<p>I finally wrapped my head around KiCad for designing and ordering circuits. Join the journey to my first own <a href="https://en.wikipedia.org/wiki/Printed_circuit_board">PCB</a>!</p>

<h3>Contents</h3>

<ul>
<li><a href="#motivation">Motivation</a></li>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#prototype">Prototype</a></li>
<li><a href="#circuit1">Circuit 1 - ChOps+mute+attenuate</a></li>
<li><a href="#circuit2"> Circuit 2 - ChOps+network</a></li>
<li><a href="#order-pcb">Order PCB</a></li>
<li><a href="#build">Build</a></li>
<li><a href="#conclusion">Conclusion</a></li>
<li><a href="#vision">Vision</a></li>
</ul>

<h2>Motivation<a id='motivation'/></h2>

<p>What I really like about synthesizer and <a href="https://en.wikipedia.org/wiki/Eurorack">eurorack</a> in particular is to have control about literally anything.
When it comes to actually performing with a patched eurorack, I missed to have some arrangement controls such as
mute and volume per channel. Modules aren&rsquo;t cheap and I wasn&rsquo;t sure what I actually wanted.</p>

<p>This thought was long time locked in my not-so-soon-todo-list but got bumped up when I was at the <a href="https://why2025.org/">Why25</a> this year.
There was a workshop about getting started with <a href="https://www.kicad.org/">KiCad</a> designing a simple <a href="https://en.wikipedia.org/wiki/Multivibrator#/media/File:Transistor_Multivibrator.svg">astable multivibrator</a> (oscilates between two outputs) which I attended.
I tried to use KiCad before, but if you don&rsquo;t know where to click, it&rsquo;s not intuitive how the workflow works.</p>

<p>This workshop changed that.</p>

<p>I recently had the opportuninty to sit together with some colleagues to get things going. Special thanks to <a href="https://github.com/apricote">apricote</a> helping me
with KiKad and <a href="https://jlcpcb.com">JLCPCB</a>.</p>

<h2>Requirements<a id='requirements'/></h2>

<p>Since this project wasn&rsquo;t about the actual functionality of the circuit but to get firm with the workflow, I limited
the requirements pretty strict to keep focus on the goal:</p>

<ul>
<li>passive, no power-supply</li>
<li>mono audio, default for eurorack</li>
<li>simple naive circuit: don&rsquo;t care about protection or filtering noise and other signal disturbances</li>
<li>easy soldering: <a href="https://en.wikipedia.org/wiki/Through-hole_technology">hrough Hole only</a>, no <a href="https://en.wikipedia.org/wiki/Surface-mount_technology">SMD</a></li>
<li>presumly use components already owned</li>
</ul>

<h2>Prototype <a id='prototype'/></h2>

<p>Where to begin? I dumped my brain into a mind map. There are no bad ideas. In fact negative feedback or cancling train of thought can
kill the flow. First comes extrapolation and then filtering based on our requirements.</p>

<p><img src="design-audio-pcbs-with-kicad_brainstorming1.png"/></p>

<p>I came up with a &ldquo;slice of an audio mixer&rdquo;: mono input, mono output, mute and attenuate. The circuit is simple, but
the functionality is quite handy. All parts are already around like fader for attenuation and push buttons for the mute.</p>

<p>ChatGPT suggested me to put fader and mute in series, pull down both to ground and add at least one capacitor at the output to
smooth out dc voltages.</p>

<p><img src="design-audio-pcbs-with-kicad_brainstorming2.png"/></p>

<p>Then fader and button got mounted onto a prototyping board and the circuit hooked up to my euroack.</p>

<p><img src="design-audio-pcbs-with-kicad_impressions.jpg"/>
<img src="design-audio-pcbs-with-kicad_prototype.jpg"/></p>

<p>It worked like a charm \0/</p>

<h2>Circuit 1 - ChOps+mute+attenuate<a id="circuit1"/></h2>

<p><img src="design-audio-pcbs-with-kicad_kicad.jpg"/>
<img src="design-audio-pcbs-with-kicad_mute_attenuate_preview.png"/></p>

<p>This is basically the direct outcome of the brainstorming from the previous section.</p>

<h2>Circuit 2 - ChOps+network<a id='circuit2'/></h2>

<p>After finalizing the first circuit so quickly I thought about a second one.
Originally I planned to do a dead simple passive multiple where all audio jacks
are just connected to each other. Since there is no inner logic, all jacks can be used both as input and output.</p>

<p>Then I thought about muting each jack individually with a push button.</p>

<p>But wait! The push button can not only intercept a connection but switch between two states! Originally I wanted to
use the second one to pull down the input to ground like I did with my <a href="#circuit1">first circuit</a>. Why not switching
between two networks instead? Like using multiple clock sources as input and kick+snare as output and whenver you decide to
disable one clock input for the kick, it  gets enabled for the snare. The possibilities are endless!</p>

<p>But wait! There is even more! Since the minimum order quantity is five, why not link them together to extend the networks?
Each board has two extension stereo jacks. each channel contains one network and daisy chains them to the next board.</p>

<h2>Order PCBs<a id='order-pcb'/></h2>

<p>The KiCad Plugin <a href="https://github.com/bennymeg/Fabrication-Toolkit">Fabrication Tooikit</a> simplifies the export with a press of a button. The resulting
<a href="https://en.wikipedia.org/wiki/Gerber_format">gerber files</a> (zip archive) can already be uploaded to a manufacturer like <a href="https://jlcpcb.com">JLCPCB</a>.</p>

<p>Right after the upload, we&rsquo;re almost ready to order:</p>

<p><img src="design-audio-pcbs-with-kicad_jlcpcb_order.png"/></p>

<p>Additional settings:</p>

<ul>
<li>Surface Finish: <code>Lead Free HASL</code>, I avoid lead as much as possible as it&rsquo;s easily poisonous</li>
<li>Color: blue for <a href="#circuit1">Circuit 1</a>, black for <a href="circuit2">Circuit 2</a></li>
</ul>

<h2>Build<a id='build'/></h2>

<p><img src="design-audio-pcbs-with-kicad_pcb_chops_attenuate.png"/>
Footprints of <a href="#circuit1">Circuit 1</a> were off for switch and fader. I could hot-fix the fader, as the footprint was just too short.
The switch accidentally has the footprint of a small guitar effect bypass foot-switch. Note: Be careful on selecting footprints. In fact
use common components where footprints exist.</p>

<p><img src="design-audio-pcbs-with-kicad_pcb_chopd_network.png"/>
<a href="#circuit2">Circuit 2</a> also had the wrong footprints for the switch. I corrected it and reordered the PCB. Next version worked just fine!</p>

<h2>Conclusion<a id='conclusion'/></h2>

<p>Making my first own PCB was way more easier than I thought. It felt similar to do a 3d printing project. You start with an idea, prototype and hold the final product in your hands. The feedback loop on the other hand is quite large due to the shipping time.</p>

<p>KiCad is quite handy when you know which parts can be skipped and are irrelevant to the process. Finding the right footprint can be pain. In my next project, I&rsquo;d first choose the components either laying around or at the seller of your desire. Doing it the other way around and searching for a component matching the footprint adds more unnecessary complexity to the workflow.</p>

<h2>Vision<a id='vision'/></h2>

<ul>
<li>design more</li>
<li>add more complex artworks with different colors/layers</li>
<li>enhance existing/more revisions</li>
<li>teach others to make their own</li>
</ul>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 03 Feb 2026 06:00:00 +0100</pubDate>
    </item>
    <item>
      <title>explore Float::INFINITY</title>
      <link>https://evilcookie.de/explore-floatinfinity.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>explore Float::INFINITY</h1>

<p>I was looking for an approach letting a client endlessly reconnect. The reconnect option just accepts numbers <code>&gt;=0</code>. The naive idea was to set it to an arbitrarily high number, but how many reconnects are enough?</p>

<p>Ruby has a concept for that: <code>Float::INFINITY</code>. The client doesn’t need to know this concept in order to work with it. The attempt count just got compared to the given value and any number is lower than infinity. In fact, adding and subtracting is also implemented.</p>

<p>Some further experiments:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="p">:</span><span class="mo">001</span><span class="o"></span><span class="o">&gt;</span> <span class="err">∞</span> <span class="o">=</span> <span class="nb">Float</span><span class="o">::</span><span class="no">INFINITY</span>
</span></span><span class="line"><span class="cl"><span class="o">=</span><span class="o">&gt;</span> <span class="no">Infinity</span>
</span></span><span class="line"><span class="cl"><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="p">:</span><span class="mo">002</span><span class="o"></span><span class="o">&gt;</span> <span class="err">∞</span> <span class="o">-</span> <span class="err">∞</span>
</span></span><span class="line"><span class="cl"><span class="o">=</span><span class="o">&gt;</span> <span class="no">NaN</span>
</span></span><span class="line"><span class="cl"><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="p">:</span><span class="mo">003</span><span class="o"></span><span class="o">&gt;</span> <span class="err">∞</span> <span class="o">+</span> <span class="err">∞</span>
</span></span><span class="line"><span class="cl"><span class="o">=</span><span class="o">&gt;</span> <span class="no">Infinity</span>
</span></span><span class="line"><span class="cl"><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="p">:</span><span class="mo">004</span><span class="o"></span><span class="o">&gt;</span> <span class="err">∞</span> <span class="o">*</span> <span class="err">∞</span>
</span></span><span class="line"><span class="cl"><span class="o">=</span><span class="o">&gt;</span> <span class="no">Infinity</span>
</span></span><span class="line"><span class="cl"><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="p">:</span><span class="mo">005</span><span class="o"></span><span class="o">&gt;</span> <span class="err">∞</span> <span class="o">/</span> <span class="err">∞</span>
</span></span><span class="line"><span class="cl"><span class="o">=</span><span class="o">&gt;</span> <span class="no">NaN</span>
</span></span><span class="line"><span class="cl"><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="p">:</span><span class="mo">006</span><span class="o"></span><span class="o">&gt;</span> <span class="err">∞</span> <span class="o">*</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="o"></span><span class="o">=</span><span class="o">&gt;</span> <span class="no">NaN</span>
</span></span><span class="line"><span class="cl"><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="p">:</span><span class="mo">007</span><span class="o"></span><span class="o">&gt;</span> <span class="err">∞</span> <span class="o">/</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="o"></span><span class="o">=</span><span class="o">&gt;</span> <span class="no">Infinity</span>
</span></span><span class="line"><span class="cl"><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="p">:</span><span class="mo">00</span><span class="o"></span><span class="mi">8</span><span class="o"></span><span class="o">&gt;</span> <span class="mi">0</span> <span class="o">/</span> <span class="err">∞</span>
</span></span><span class="line"><span class="cl"><span class="o">=</span><span class="o">&gt;</span> <span class="mi">0</span><span class="o"></span><span class="o">.</span><span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="o"></span></span></span></code></pre>
<h2>to_i issue</h2>

<p>If ruby clients like <a href="https://github.com/redis/redis-rb">redis</a> apply <code>to_i</code> onto the given value, our approach raises an exception as infinity is not a valid integer&hellip;</p>

<p>As I&rsquo;ve lost my idealism over the past years to get more practical, we just can use the maximal possible positive
integer 4611686018427387903<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. The calculation from <a href="https://stackoverflow.com/a/736313">this SO answer</a> goes like this:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">.- every binary digit can have (as the word binary implies) two states: 0 and 1. base ** digits is the general formula to calculate
</span></span><span class="line"><span class="cl">|  the maximal possible decimal number with a defined base (10,2,8,16, you name it) and digits. Note that the digits is the count of
</span></span><span class="line"><span class="cl">|  the digits within the base.
</span></span><span class="line"><span class="cl">|
</span></span><span class="line"><span class="cl">|     .- the maximum bitwidth of the local architecture, mostly 64-bit nowadays
</span></span><span class="line"><span class="cl">|     |       
</span></span><span class="line"><span class="cl">|     |          .- one signed bit (as usual for signed ints) and one internal bit so ruby knows its either a pointer or object 
</span></span><span class="line"><span class="cl">|     |          |
</span></span><span class="line"><span class="cl">|     |          |    .- &#39;0&#39; itself belongs to count of possible numbers, so the highest number must be 1 less
</span></span><span class="line"><span class="cl">|     |          |    |
</span></span><span class="line"><span class="cl">v     v          v    v
</span></span><span class="line"><span class="cl">2 ** (bitwidth - 2) - 1 =
</span></span><span class="line"><span class="cl">2 ** (bytewidth * 8 - 2) - 1 =
</span></span><span class="line"><span class="cl">2 ** (0.size * 8 - 2) -1 =
</span></span><span class="line"><span class="cl">4_611_686_018_427_387_903
</span></span></code></pre>
<h3>why this approach is bad in general</h3>

<p>Assuming numbers should be last resort as they age badly. E.g. if the timeouts gets set to zero and the future CPU has the power,
then that amount of retries might be reached faster than you thought in the first place.</p>

<p>My advice is to add a // TODO comment to tell your future self why you did this. You&rsquo;ll thank me debugging the next major outage that
leads you to some magical numbers (those are basically the definition of assumed numbers).</p>

<p><small style="color:rgba(0,0,0,0)">+hf</small></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">If your system needs more retries than that, you may have greater problems&hellip;</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Thu, 09 Oct 2025 06:00:00 +0200</pubDate>
    </item>
    <item>
      <title>hexdump pattern</title>
      <link>https://evilcookie.de/hexdump-pattern.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>hexdump pattern</h1>

<p><img src="hexdump-pattern_hexdump_small.png"/></p>

<p>I find myself surprisingly often in situations where I want to inspect byte buffers.</p>

<p>Luckily my <a href="https://www2.htw-dresden.de/~beck/PSPI/praktika/praktC2.html">first programming lesson</a> from my cs studies taught me a pretty good hexdump pattern[^1]:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">hexdump</span><span class="p">(</span><span class="nx">buf</span> <span class="p">[</span><span class="p">]</span><span class="kt">byte</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// the hexdump print loop, for each row
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">for</span> <span class="nx">row</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">row</span> <span class="p">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="nx">buf</span><span class="p">)</span><span class="p">;</span> <span class="nx">row</span> <span class="o">+=</span> <span class="mi">16</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;%04x | &#34;</span><span class="p">,</span> <span class="nx">row</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// print hex value of each field in the current row
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="k">for</span> <span class="nx">field</span> <span class="o">:=</span> <span class="nx">row</span><span class="p">;</span> <span class="nx">field</span> <span class="p">&lt;</span> <span class="nx">row</span><span class="o">+</span><span class="mi">16</span> <span class="o">&amp;&amp;</span> <span class="nx">field</span> <span class="p">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="nx">buf</span><span class="p">)</span><span class="p">;</span> <span class="nx">field</span> <span class="o">+=</span> <span class="mi">1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// separate 8 byte chunks (offset by 8 to not print the separater
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="c1">// before the first byte of a row)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="k">if</span> <span class="p">(</span><span class="nx">field</span><span class="o">+</span><span class="mi">8</span><span class="p">)</span><span class="o">%</span><span class="mi">16</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34; &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">			<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;%02x &#34;</span><span class="p">,</span> <span class="nx">buf</span><span class="p">[</span><span class="nx">field</span><span class="p">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Print</span><span class="p">(</span><span class="s">&#34;| &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// print ascii value of each field of the current if printable
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="k">for</span> <span class="nx">field</span> <span class="o">:=</span> <span class="nx">row</span><span class="p">;</span> <span class="nx">field</span> <span class="p">&lt;</span> <span class="nx">row</span><span class="o">+</span><span class="mi">16</span> <span class="o">&amp;&amp;</span> <span class="nx">field</span> <span class="p">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="nx">buf</span><span class="p">)</span><span class="p">;</span> <span class="nx">field</span> <span class="o">+=</span> <span class="mi">1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="p">(</span><span class="nx">field</span><span class="o">+</span><span class="mi">8</span><span class="p">)</span><span class="o">%</span><span class="mi">16</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34; &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// space (20) and tilde (126) are the boundaries of the printable
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="c1">// ascii table
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="k">if</span> <span class="nx">buf</span><span class="p">[</span><span class="nx">field</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="sc">&#39; &#39;</span> <span class="o">&amp;&amp;</span> <span class="nx">buf</span><span class="p">[</span><span class="nx">field</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="sc">&#39;~&#39;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;%c&#34;</span><span class="p">,</span> <span class="nx">buf</span><span class="p">[</span><span class="nx">field</span><span class="p">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="nx">fmt</span><span class="p">.</span><span class="nf">Print</span><span class="p">(</span><span class="s">&#34;.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Let&rsquo;s say we generate an exemplary buffer with numbers 0 to a full byte of 256 (0xff):</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// exemplary bytes from 0x00 to 0xff
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">buf</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="p">[</span><span class="p">]</span><span class="kt">byte</span><span class="p">,</span> <span class="mh">0x100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="nx">buf</span><span class="p">)</span><span class="p">;</span> <span class="nx">i</span> <span class="o">+=</span> <span class="mi">1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">buf</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="p">=</span> <span class="nb">byte</span><span class="p">(</span><span class="nx">i</span> <span class="o">%</span> <span class="mh">0x100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nf">hexdump</span><span class="p">(</span><span class="nx">buf</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Output:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">0000 | 00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f | ........ ........
</span></span><span class="line"><span class="cl">0010 | 10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f | ........ ........
</span></span><span class="line"><span class="cl">0020 | 20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f |  !&#34;#$%&amp;&#39; ()*+,-./
</span></span><span class="line"><span class="cl">0030 | 30 31 32 33 34 35 36 37  38 39 3a 3b 3c 3d 3e 3f | 01234567 89:;&lt;=&gt;?
</span></span><span class="line"><span class="cl">0040 | 40 41 42 43 44 45 46 47  48 49 4a 4b 4c 4d 4e 4f | @ABCDEFG HIJKLMNO
</span></span><span class="line"><span class="cl">0050 | 50 51 52 53 54 55 56 57  58 59 5a 5b 5c 5d 5e 5f | PQRSTUVW XYZ[\]^_
</span></span><span class="line"><span class="cl">0060 | 60 61 62 63 64 65 66 67  68 69 6a 6b 6c 6d 6e 6f | `abcdefg hijklmno
</span></span><span class="line"><span class="cl">0070 | 70 71 72 73 74 75 76 77  78 79 7a 7b 7c 7d 7e 7f | pqrstuvw xyz{|}~.
</span></span><span class="line"><span class="cl">0080 | 80 81 82 83 84 85 86 87  88 89 8a 8b 8c 8d 8e 8f | ........ ........
</span></span><span class="line"><span class="cl">0090 | 90 91 92 93 94 95 96 97  98 99 9a 9b 9c 9d 9e 9f | ........ ........
</span></span><span class="line"><span class="cl">00a0 | a0 a1 a2 a3 a4 a5 a6 a7  a8 a9 aa ab ac ad ae af | ........ ........
</span></span><span class="line"><span class="cl">00b0 | b0 b1 b2 b3 b4 b5 b6 b7  b8 b9 ba bb bc bd be bf | ........ ........
</span></span><span class="line"><span class="cl">00c0 | c0 c1 c2 c3 c4 c5 c6 c7  c8 c9 ca cb cc cd ce cf | ........ ........
</span></span><span class="line"><span class="cl">00d0 | d0 d1 d2 d3 d4 d5 d6 d7  d8 d9 da db dc dd de df | ........ ........
</span></span><span class="line"><span class="cl">00e0 | e0 e1 e2 e3 e4 e5 e6 e7  e8 e9 ea eb ec ed ee ef | ........ ........
</span></span><span class="line"><span class="cl">00f0 | f0 f1 f2 f3 f4 f5 f6 f7  f8 f9 fa fb fc fd fe ff | ........ ........
</span></span></code></pre>
<p><small style="color:rgba(0,0,0,0)">+hf</small></p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 24 Sep 2025 12:00:00 +0200</pubDate>
    </item>
    <item>
      <title>Lets build a Hypervisor with KVM</title>
      <link>https://evilcookie.de/lets-build-a-hypervisor-with-kvm.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Let&rsquo;s build a hypervisor with KVM</h1>

<p><img src="lets-build-a-hypervisor-with-kvm_kvm_title_edited.png"/></p>

<p>There are a bunch of common challenges on a bucket list of a software developer:</p>

<ul>
<li>compiler/interpreter</li>
<li>operating system</li>
<li>regex parser</li>
<li>http server</li>
<li>OpenGL (probably Vulkan now) graphic/game engine</li>
<li>let an LED blink</li>
</ul>

<p>Recently, I got another one that deserves more attention:</p>

<p><em>Build your own Hypervisor and boot a Virtual Machine.</em></p>

<p>What sounds like a mammoth of a project, is actually quite feasible using Linux&rsquo;s KVM API. At the end of this post you&rsquo;ll find yourself running your own bootloader within a VM. Use <a href="https://github.com/RaphaelPour/matrix">matrix</a> if you just want to play around.</p>

<h3>Contents</h3>

<ul>
<li><a href="#virtualization">Virtualization</a>

<ul>
<li><a href="#paravirtualization">Paravirtualization</a></li>
<li><a href="#kvm-api">KVM API</a></li>
</ul></li>
<li><a href="#implementation">Implementation</a>

<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#access">Access the KVM API</a></li>
<li><a href="#create-vm">Create a VM with VCPU</a></li>
<li><a href="#run-structure">Map run structure</a></li>
<li><a href="#memory">Add memory</a></li>
<li><a href="#registers-and-segments">Initialize the registers and segments</a></li>
<li><a href="#smallest-bootloader">Smallest bootloader in the world</a></li>
<li><a href="#matrix">Enter the matrix</a></li>
<li><a href="#exit-reasons">Exit reasons</a></li>
<li><a href="#bootloader">Write bootloader with nasm</a></li>
<li><a href="#print-guest-output">Print output from the guest</a></li>
</ul></li>
<li><a href="#matrix">Matrix</a></li>
<li><a href="#vision">Vision</a></li>
<li><a href="#summary">Summary</a></li>
<li><a href="#">Appendix</a>

<ul>
<li><a href="#full-program">full program</a></li>
<li><a href="#ioctl-helper">ioctl helper</a></li>
<li><a href="#references">References</a></li>
<li><a href="#glossary">Glossary</a></li>
</ul></li>
</ul>

<h2>Virtualization<a id='virtualization'/></h2>

<p>Emulate hardware using software to run operating systems just like on real hardware. An instance of an emulated system is called virtual machine, or VM for short. The real machine on which the virtualization takes place is called host, while the emulated system is called guest. Hypervisor is the software providing the virtual machine.</p>

<p>Can operating systems tell if they&rsquo;re just in a virtual machine? Theoretically not, as the emulated hardware should behave exactly as it&rsquo;s real counterpart. In practice the guest can use <a href="https://lwn.net/Articles/301888/">cpuid</a> or <a href="https://en.wikipedia.org/wiki/Desktop_Management_Interface">dmi</a>, for example via <a href="https://www.man7.org/linux/man-pages/man1/systemd-detect-virt.1.html">systemd-detect-virt</a>. It&rsquo;s <a href="https://github.com/systemd/systemd/blob/main/src/basic/virt.c">source</a> clearly shows how this works for each architecture.</p>

<p>The issue with emulation is the translation layer, slowing down the performance. This is where paravirtualization comes into play.</p>

<h3>Paravirtualization<a id='paravirtualization'/></h3>

<p>While emulation is about rebuilding hardware within software, paravirtualization is quite the opposite:
pass the real hardware through to the guest.</p>

<p>This also accelerates the performance of a virtual machine a lot, while the translation layer is not necessary anymore.</p>

<p>The virtual machine is still isolated and the kernel grants it its own memory regions and virtual cpus.</p>

<h3>KVM API<a id='kvm-api'/></h3>

<p>The Kernel Virtual Machine API (KVM for short) provides a set of functions to create and operate on virtual machines.
The API can be accessed via <code>/dev/kvm</code> using <code>ioctl</code> operations.</p>

<p>The main steps summarized:</p>

<ol>
<li>open <code>/dev/kvm</code> and compare version</li>
<li>processing unit: create VM with vcpu</li>
<li>get run status struct</li>
<li>allocate memory region and load bootable image</li>
<li>initialize registers and segments</li>
<li>run VM and respond to guest requests (like IO or shutdown)</li>
<li>do 6. repeateadly until the guest wants to halt</li>
</ol>

<h2>Implementation<a id='implementation'/></h2>

<p>As usual these days<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>, I chose Golang. The implementation follows roughly the summarized steps from the previous section.</p>

<p>The complete program can be found at <a href="#full-program">the end</a>.</p>

<h3>Requirements<a id='requirements'/></h3>

<ul>
<li>host must support kvm:

<ul>
<li>check: <code>/dev/kvm</code> exist, kvm kernel module exists (<code>lsmod|grep kvm</code>)</li>
<li>virtualized environments like cloud servers probably don&rsquo;t support this<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup></li>
</ul></li>
<li>x86 host<sup class="footnote-ref" id="fnref:arm"><a href="#fn:arm">3</a></sup></li>
<li>go toolchain (tested with go version 1.24.0 and platform linux_amd64)</li>
<li>Copy <code>ioctl.go</code> from the appendix. It&rsquo;s my ported version of <code>include/asm-generic/ioctl.h</code> directives used for all the KVM consts defined in <code>include/linux/kvm.h</code>.</li>
</ul>

<h3>Access the KVM API<a id='access'/></h3>

<p>Open the kvm  device and check the ABI version, which needs to be 12 or higher:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;os&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;syscall&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// latest stable abi version
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">KVM_VERSION</span> <span class="p">=</span> <span class="mi">12</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// linux/kvm.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">KVMIO</span>                      <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mh">0xAE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_GET_API_VERSION</span>        <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IO</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">)</span><span class="p">)</span> <span class="c1">// -&gt; 0xAE00
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">fd</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="s">&#34;/dev/kvm&#34;</span><span class="p">,</span> <span class="nx">os</span><span class="p">.</span><span class="nx">O_RDWR</span><span class="p">,</span> <span class="mo">0600</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;open:&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">defer</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Close</span><span class="p">(</span><span class="nx">fd</span><span class="p">)</span><span class="p">;</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;close:&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">kvmVersion</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">fd</span><span class="p">)</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">KVM_GET_API_VERSION</span><span class="p">)</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;ioctl:&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">kvmVersion</span> <span class="o">==</span> <span class="nx">KVM_VERSION</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;kvm version %d supported\n&#34;</span><span class="p">,</span> <span class="nx">kvmVersion</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;kvm version %d is too old, need %d or newer\n&#34;</span><span class="p">,</span> <span class="nx">kvmVersion</span><span class="p">,</span> <span class="nx">KVM_VERSION</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<ul>
<li>on success, the above program should print something like <code>kvm version 12 supportd</code></li>
<li>version 12 is the first stable ABI version and hasn&rsquo;t changed since 2007<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">4</a></sup>, this can be skipped on modern systems</li>
<li>the <code>KVM_GET_API_VERSION</code> operation code comes from the kvm header file, we&rsquo;ll use more from there later</li>
<li>since the api is exposed over linux&rsquo;s <a href="https://en.wikipedia.org/wiki/File_system_API">File system API</a>, we use file descriptors for references. This is not the go way, and we need to interpret the integer as pointer (<code>uintptr</code>) whenever we do a syscall.</li>
<li>the ioctl syscall takes three arguments:

<ul>
<li>file descriptor of device we want operate on</li>
<li>the command code</li>
<li>command-specific argument or nil if none is needed.</li>
</ul></li>
</ul>

<h3>Create a VM with VCPU<a id='create-vm'/></h3>

<p>Using the kvm reference, we can now create a VM followed by a vcpu:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;os&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;syscall&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_VERSION</span> <span class="p">=</span> <span class="mi">12</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// linux/kvm.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">KVMIO</span>                      <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mh">0xAE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_GET_API_VERSION</span>        <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IO</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">)</span><span class="p">)</span> <span class="c1">// -&gt; 0xAE00
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">KVM_CREATE_VM</span>              <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IO</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_CREATE_VCPU</span>            <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IO</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x41</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">kvm</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="s">&#34;/dev/kvm&#34;</span><span class="p">,</span> <span class="nx">os</span><span class="p">.</span><span class="nx">O_RDWR</span><span class="p">,</span> <span class="mo">0600</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;can&#39;t open kvm device: %s\n&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">defer</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Close</span><span class="p">(</span><span class="nx">kvm</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// check for stable kvm abi, needs to be &gt;=12
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">kvmVersion</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">kvm</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_GET_API_VERSION</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">			<span class="s">&#34;errror getting kvm api version %d\n&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nx">errno</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">kvmVersion</span> <span class="o">!=</span> <span class="nx">KVM_VERSION</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">			<span class="s">&#34;kvm version %d is too old, need %d or newer\n&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nx">kvmVersion</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nx">KVM_VERSION</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">vm</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">kvm</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_CREATE_VM</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">			<span class="s">&#34;errror creating vm %d\n&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nx">errno</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">defer</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Close</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="nx">vm</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">vcpu</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vm</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_CREATE_VCPU</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">			<span class="s">&#34;errror creating vcpu %d\n&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nx">errno</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">defer</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Close</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="nx">vm</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;kvm-fd=%d vm-fd=%d vcpu-fd=%d\n&#34;</span><span class="p">,</span> <span class="nx">kvm</span><span class="p">,</span> <span class="nx">vm</span><span class="p">,</span> <span class="nx">vcpu</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<ul>
<li>we add two more operation codes <code>KVM_CREATE_VM</code> and <code>KVM_CREATE_VCPU</code> to create a vm and vcpu respectively</li>
<li>the VM gets created using the kvm reference, while the vcpu gets created with the VM reference. We could also create multiple VMs or multiple vcpus per VM here.</li>
<li>verification: program outputs something like <code>kvm-fd=3 vm-fd=4 vcpu-fd=5</code><sup class="footnote-ref" id="fnref:4"><a href="#fn:4">5</a></sup></li>
</ul>

<h3>Map run structure<a id='run-structure'/></h3>

<p>The status of the virtual machine is contained in the <code>kvm_run</code> struct. This is especially needed when the VM interrupts and requests the host to do something (like IO). Before running the VM, we need to map the struct into user-space:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;os&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;syscall&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">KVM_VERSION</span> <span class="p">=</span> <span class="mi">12</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// linux/kvm.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">KVMIO</span>                      <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mh">0xAE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">KVM_GET_API_VERSION</span>        <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IO</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">)</span><span class="p">)</span> <span class="c1">// -&gt; 0xAE00
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">KVM_CREATE_VM</span>              <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IO</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">KVM_GET_VCPU_MMAP_SIZE</span>     <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IO</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">KVM_CREATE_VCPU</span>            <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IO</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x41</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">kvm_run</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">_</span>          <span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="kt">byte</span>
</span></span><span class="line"><span class="cl">  <span class="nx">exitReason</span> <span class="kt">uint32</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// open kvm and check version...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// create vm, vcpu
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="c1">// map kvmrun into user-space memory
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">kvmRunSize</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">kvm</span><span class="p">)</span><span class="p">,</span> <span class="nx">c</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">rawKvmRun</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Mmap</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">   <span class="nb">int</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">   <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">   <span class="nb">int</span><span class="p">(</span><span class="nx">kvmRunSize</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">   <span class="nx">syscall</span><span class="p">.</span><span class="nx">PROT_READ</span><span class="p">|</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">PROT_WRITE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">   <span class="nx">syscall</span><span class="p">.</span><span class="nx">MAP_SHARED</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;error mapping kvm run: %s\n&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">kvmRun</span> <span class="o">:=</span> <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">kvm_run</span><span class="p">)</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">rawKvmRun</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">kvmRun</span><span class="p">.</span><span class="nx">exitReason</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<ul>
<li>altough the size of the run structure is pretty constant, we query it via <code>KVM_GET_VCPU_MMAP_SIZE</code></li>
<li><code>*(*goType)(unsafe.Pointer(&amp;bytes[offset]))</code>: dirty hack to convert a byte buffer into a go type. The usual C stuff&hellip;</li>
<li>verification: no error and program prints exit-reason 0</li>
</ul>

<h3>Add memory<a id='memory'/></h3>

<p>Next we allocate some memory for the guest. In this example we reserve 1Mib (or <code>100000</code> hex) and load the given image file into it:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;os&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;syscall&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;unsafe&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">GUEST_MEMORY</span> <span class="p">=</span> <span class="mh">0x100000</span> <span class="c1">// 1Mib
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">KVM_VERSION</span>  <span class="p">=</span> <span class="mi">12</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// linux/kvm.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// KVM_...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">KVM_SET_USER_MEMORY_REGION</span> <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IOW</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x46</span><span class="p">,</span> <span class="nx">unsafe</span><span class="p">.</span><span class="nf">Sizeof</span><span class="p">(</span><span class="nx">KVMUserspaceMemoryRegion</span><span class="p">{</span><span class="p">}</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// kvm_run ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// kvm_userspace_memory_region from linux/kvm.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">KVMUserspaceMemoryRegion</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Slot</span>          <span class="kt">uint32</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Flags</span>         <span class="kt">uint32</span>
</span></span><span class="line"><span class="cl">  <span class="nx">GuestPhysAddr</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">  <span class="nx">MemorySize</span>    <span class="kt">uint64</span> <span class="cm">/* bytes */</span>
</span></span><span class="line"><span class="cl">  <span class="nx">UserspaceAddr</span> <span class="kt">uint64</span> <span class="cm">/* start of the userspace allocated memory */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// expect image file as first argument
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">2</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;usage: %s &lt;image&gt;\n&#34;</span><span class="p">,</span> <span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// open kvm and check version...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// create vm, vcpu
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// map kvmrun into user-space memory
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">  <span class="c1">// load first argument 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">image</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">os</span><span class="p">.</span><span class="nf">ReadFile</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;error loading image: %s\n&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// allocate guest memory
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">guestMemory</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Mmap</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="c1">// ignored because of MAP_ANONYMOUS
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">GUEST_MEMORY</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">syscall</span><span class="p">.</span><span class="nx">PROT_READ</span><span class="p">|</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">PROT_WRITE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">syscall</span><span class="p">.</span><span class="nx">MAP_ANONYMOUS</span><span class="p">|</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">MAP_PRIVATE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;error allocating guest memory: %s\n&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// copy embedded image
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nb">copy</span><span class="p">(</span><span class="nx">guestMemory</span><span class="p">,</span> <span class="nx">image</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">memoryRegion</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">KVMUserspaceMemoryRegion</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">Slot</span><span class="p">:</span>          <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">Flags</span><span class="p">:</span>         <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">GuestPhysAddr</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">MemorySize</span><span class="p">:</span>    <span class="nb">uint64</span><span class="p">(</span><span class="nx">GUEST_MEMORY</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">UserspaceAddr</span><span class="p">:</span> <span class="nb">uint64</span><span class="p">(</span><span class="nb">uintptr</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">guestMemory</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">)</span><span class="p">)</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vm</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_SET_USER_MEMORY_REGION</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="nx">memoryRegion</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;error setting memory region: %d\n&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<ul>
<li>KVMUserspaceMemoryRegion declares the relation between host and guest memory address space</li>
<li>host memory starts at the pointer of the allocated memory</li>
<li>guest starts at zero, which is the beginning of its address space, if we add multiple regions we could set this to an other value</li>
<li>memory size is equal for both address spaces as this is a 1:1 mapping and refers to the size of the allocated memory</li>
<li><code>KVM_SET_USER_MEMORY_REGION</code> adds a memory region to the given VM</li>
<li>verification: no error</li>
</ul>

<h3>Initialize the registers and segments<a id='registers-and-segments'/></h3>

<p>Before we can run the VM, the registers and segments of our vcpu need to be set up properly. This comes along with a bunch of structs that need to be
redefined within our go program. For completeness, I define every field although we don&rsquo;t need many.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">GUEST_MEMORY</span> <span class="p">=</span> <span class="mh">0x100000</span> <span class="c1">// 1Mib
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">KVM_VERSION</span>  <span class="p">=</span> <span class="mi">12</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// linux/kvm.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">KVM_GET_REGS</span>               <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IOR</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x81</span><span class="p">,</span> <span class="nx">unsafe</span><span class="p">.</span><span class="nf">Sizeof</span><span class="p">(</span><span class="nx">KVMRegs</span><span class="p">{</span><span class="p">}</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// not needed but for sake of completeness
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// KVM_SET_REGS               = uintptr(_IOW(KVMIO, 0x82, unsafe.Sizeof(KVMRegs{})))
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">  <span class="nx">KVM_GET_SREGS</span>              <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IOR</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x83</span><span class="p">,</span> <span class="nx">unsafe</span><span class="p">.</span><span class="nf">Sizeof</span><span class="p">(</span><span class="nx">KVMSRegs</span><span class="p">{</span><span class="p">}</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">KVM_SET_SREGS</span>              <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IOW</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x84</span><span class="p">,</span> <span class="nx">unsafe</span><span class="p">.</span><span class="nf">Sizeof</span><span class="p">(</span><span class="nx">KVMSRegs</span><span class="p">{</span><span class="p">}</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// KVM Structs (asm/kvm.h)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">KVMRegs</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">RAX</span><span class="p">,</span> <span class="nx">RBX</span><span class="p">,</span> <span class="nx">RCX</span><span class="p">,</span> <span class="nx">RDX</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">  <span class="nx">RSI</span><span class="p">,</span> <span class="nx">RDI</span><span class="p">,</span> <span class="nx">RSP</span><span class="p">,</span> <span class="nx">RBP</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">  <span class="nx">R8</span><span class="p">,</span> <span class="nx">R9</span><span class="p">,</span> <span class="nx">R10</span><span class="p">,</span> <span class="nx">R11</span>   <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">  <span class="nx">R12</span><span class="p">,</span> <span class="nx">R13</span><span class="p">,</span> <span class="nx">R14</span><span class="p">,</span> <span class="nx">R15</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">  <span class="nx">RIP</span><span class="p">,</span> <span class="nx">RFlags</span>        <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// needed for sregs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">KVMSegment</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Base</span>                           <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Limit</span>                          <span class="kt">uint32</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Selector</span>                       <span class="kt">uint16</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Tyype</span>                          <span class="kt">uint8</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Present</span><span class="p">,</span> <span class="nx">DPL</span><span class="p">,</span> <span class="nx">DB</span><span class="p">,</span> <span class="nx">S</span><span class="p">,</span> <span class="nx">L</span><span class="p">,</span> <span class="nx">G</span><span class="p">,</span> <span class="nx">AVL</span> <span class="kt">uint8</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Unusable</span>                       <span class="kt">uint8</span>
</span></span><span class="line"><span class="cl">  <span class="nx">_</span>                              <span class="kt">uint8</span> <span class="c1">// padding
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// needed for sregs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">KVMDTable</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Base</span>  <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Limit</span> <span class="kt">uint16</span>
</span></span><span class="line"><span class="cl">  <span class="nx">_</span>     <span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="kt">uint16</span> <span class="c1">//padding
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">KVMSRegs</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">CS</span><span class="p">,</span> <span class="nx">DS</span><span class="p">,</span> <span class="nx">ES</span><span class="p">,</span> <span class="nx">FS</span><span class="p">,</span> <span class="nx">GS</span><span class="p">,</span> <span class="nx">SS</span>  <span class="nx">KVMSegment</span>
</span></span><span class="line"><span class="cl">  <span class="nx">TR</span><span class="p">,</span> <span class="nx">LDT</span>                 <span class="nx">KVMSegment</span>
</span></span><span class="line"><span class="cl">  <span class="nx">GDT</span><span class="p">,</span> <span class="nx">IDT</span>                <span class="nx">KVMDTable</span>
</span></span><span class="line"><span class="cl">  <span class="nx">CR0</span><span class="p">,</span> <span class="nx">CR2</span><span class="p">,</span> <span class="nx">CR3</span><span class="p">,</span> <span class="nx">CR4</span><span class="p">,</span> <span class="nx">CR8</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Efer</span>                    <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ApicBase</span>                <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">  <span class="nx">InterruptBitmap</span>         <span class="p">[</span><span class="p">(</span><span class="mi">256</span> <span class="o">+</span> <span class="mi">63</span><span class="p">)</span> <span class="o">/</span> <span class="mi">64</span><span class="p">]</span><span class="kt">uint64</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">registers</span> <span class="o">:=</span> <span class="nx">KVMRegs</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">RIP</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">RFlags</span><span class="p">:</span> <span class="mh">0x2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_SET_REGS</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">registers</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;KVM_SET_REGS: %s\n&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// get initial state of regs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kd">var</span> <span class="nx">sregs</span> <span class="nx">KVMSRegs</span>
</span></span><span class="line"><span class="cl">  <span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_GET_SREGS</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">sregs</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;KVM_GET_SREGS: %s\n&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">sregs</span><span class="p">.</span><span class="nx">CS</span><span class="p">.</span><span class="nx">Base</span> <span class="p">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">  <span class="nx">sregs</span><span class="p">.</span><span class="nx">CS</span><span class="p">.</span><span class="nx">Selector</span> <span class="p">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_SET_SREGS</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">sregs</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;KVM_SET_REGS: %s\n&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<ul>
<li>we use 64bit, indicated by the <code>R</code> registers</li>
<li><code>RIP</code>: instruction pointer originally started at guest memory offset, but I don&rsquo;t know why because bootloader is copied to beginning of guest memory</li>
<li><code>RFlags</code>: reserved bit must be set by definition of x86 architecture, clearing it causes undefined behavior</li>
<li>sregs: described in the <a href="https://lwn.net/Articles/658511/">LWN article</a> although I didn&rsquo;t really understand it</li>
<li>verification: well, there is none other than run it successfully</li>
</ul>

<h3>Smallest bootloader in the world<a id='worlds-smallest-bootloader'/></h3>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">smallestBootloader</span> <span class="p">=</span> <span class="p">[</span><span class="p">]</span><span class="kt">byte</span><span class="p">{</span><span class="mh">0xf4</span><span class="p">}</span>
</span></span></code></pre>
<p>This bootloader immediately halts the cpu with the <code>hlt</code> instruction with <a href="https://en.wikipedia.org/wiki/X86_instruction_listings">x86 Opcode <code>f4</code></a>.</p>

<p>After our first run, I&rsquo;ll go more into detail about bootloaders.</p>

<h3>Enter the matrix<a id='matrix'/></h3>

<p>It&rsquo;s time to run our VM!</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">KVM_RUN</span>                    <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nf">_IO</span><span class="p">(</span><span class="nx">KVMIO</span><span class="p">,</span> <span class="mh">0x80</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_RUN</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;KVM_RUN: %s\n&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">kvmRun</span><span class="p">.</span><span class="nx">exitReason</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p><code>5</code> is the output we yearn for. It&rsquo;s the halt exit-reason.</p>

<p>Congratulations! You just ran your first VM \o/</p>

<h3>Exit reasons<a id='exit-reason'/></h3>

<p>Now we take a look how guest and host communicate with each other. The <code>KVM_RUN</code> command not only returns when the
VM halted. There are a bunch of other <em>reasons</em>, most notably <code>KVM_EXIT_REASON_IO</code>.</p>

<p>Every time the VM wants to access real hardware, <code>KVM_RUN</code> returns and we need to provide it. This is where device emulation comes into play like a serial uart console, vga, a real time clock or network interface.</p>

<h3>Write bootloader with nasm<a id='bootloader'/></h3>

<p>The halt program was basic enough so we could just hardcode it with opcodes. In order to be flexible and write more sophisticated bootloader, we will code all upcoming examples with assembler.</p>

<p><a href="https://evilcookie.de/lets-boot.html">As</a> <a href="https://evilcookie.de/lets-boot-with-riscv.html">always</a> I use the <a href="https://en.wikipedia.org/wiki/Netwide_Assembler">netwide assembler</a> with Intel syntax. Use <code>nasm -f bin boot.asm -o boot.bin</code> to assemble <code>boot.asm</code> into <code>boot.bin</code>. Use <code>-O0</code> to avoid optimizations in case you want to look at the binary code.</p>

<p>To test if everything works, the following bootloader just loops around and let the VM hang:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nl">loop:</span>
</span></span><span class="line"><span class="cl">    <span class="nf">jmp</span> <span class="no">loop</span>
</span></span></code></pre>
<h3>Print output from the guest<a id='print-guest-output'/></h3>

<p>Let&rsquo;s spice it up and print something the guest sent to us.</p>

<p>Luckily, we control both ends: hypervisor and guest. This makes communication a lot easier. Roll the dice and choose a port of your desire. I go with 0x42:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">mov</span> <span class="no">al</span><span class="p">,</span> <span class="err">&#34;</span><span class="c">#&#34;   ; set accumulator to the character we wanna print
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="no">mov</span> <span class="no">dx</span><span class="p">,</span> <span class="mi">0x42</span>  <span class="c">; set data register to the desired port
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="no">out</span> <span class="no">dx</span><span class="p">,</span> <span class="no">al</span>    <span class="c">; let&#39;s print
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="no">hlt</span>           <span class="c">; halt and exit guest
</span></span></span></code></pre>
<p>Now we run <code>KVM_RUN</code> in a loop and check the exit reason. On halt we do the usual exit and on IO we print the guests data:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="o">/</span><span class="o">...</span>
</span></span><span class="line"><span class="cl">  <span class="nx">KVM_EXIT_REASON_HALT</span> <span class="p">=</span> <span class="mi">5</span>
</span></span><span class="line"><span class="cl">  <span class="nx">KVM_EXIT_REASON_IO</span>   <span class="p">=</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">KVM_IO_IN</span>  <span class="p">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">  <span class="nx">KVM_IO_OUT</span> <span class="p">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">KVMRun</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">_</span>          <span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="kt">byte</span>
</span></span><span class="line"><span class="cl">  <span class="nx">exitReason</span> <span class="kt">uint32</span>
</span></span><span class="line"><span class="cl">  <span class="nx">_</span>          <span class="p">[</span><span class="mi">20</span><span class="p">]</span><span class="kt">byte</span>
</span></span><span class="line"><span class="cl">  <span class="nx">details</span>    <span class="p">[</span><span class="mi">256</span><span class="p">]</span><span class="kt">byte</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">KVMExitIO</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Direction</span>  <span class="kt">uint8</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Size</span>       <span class="kt">uint8</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Port</span>       <span class="kt">uint16</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Count</span>      <span class="kt">uint32</span>
</span></span><span class="line"><span class="cl">  <span class="nx">DataOffset</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_RUN</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;KVM_RUN: %s\n&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;exit-reason=%d\n&#34;</span><span class="p">,</span> <span class="nx">kvmRun</span><span class="p">.</span><span class="nx">exitReason</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_RUN</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;KVM_RUN: %s\n&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">switch</span> <span class="nx">kvmRun</span><span class="p">.</span><span class="nx">exitReason</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;sometimes things get complicated&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nx">KVM_EXIT_REASON_HALT</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nx">KVM_EXIT_REASON_IO</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="nx">ioDetails</span> <span class="o">:=</span> <span class="p">(</span><span class="o">*</span><span class="nx">KVMExitIO</span><span class="p">)</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">kvmRun</span><span class="p">.</span><span class="nx">details</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="nx">start</span> <span class="o">:=</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">[</span><span class="p">]</span><span class="kt">byte</span><span class="p">)</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">kvmRun</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="nx">ioDetails</span><span class="p">.</span><span class="nx">Direction</span> <span class="o">==</span> <span class="nx">KVM_IO_OUT</span> <span class="o">&amp;&amp;</span> <span class="nx">ioDetails</span><span class="p">.</span><span class="nx">Port</span> <span class="o">==</span> <span class="mh">0x42</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nb">string</span><span class="p">(</span><span class="nx">start</span><span class="p">[</span><span class="nx">ioDetails</span><span class="p">.</span><span class="nx">DataOffset</span><span class="p">]</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;unhandeled exit reason&#34;</span><span class="p">,</span> <span class="nx">kvmRun</span><span class="p">.</span><span class="nx">exitReason</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<ul>
<li>code <code>2</code> indicate an io request from the guest</li>
<li>extend the <code>KVMRun</code> struct with <code>details</code> containing details about the requested io operation

<ul>
<li><code>direction</code>: indicates if it&rsquo;s an input <code>0</code> or output <code>1</code> operation</li>
<li><code>size</code>: buffersize to read/write</li>
<li><code>port</code>: each hardware component has it&rsquo;s own port</li>
<li><code>count</code>: ??</li>
<li><code>data offset</code>: offset starting from the kvm_run struct address to the actual data</li>
</ul></li>
</ul>

<h2>Matrix<a id='matrix'/></h2>

<p>I&rsquo;ve consolidated everything into a repo <a href="https://github.com/RaphaelPour/matrix">matrix</a>. It comes with an interactive shell to step through the KVM_RUN invocations and dump the registers.</p>

<h2>Vision<a id='vision'/></h2>

<ul>
<li>basic driver: serial console, realtime clock</li>
<li>single-step debugger</li>
<li>support more exit reasons</li>
</ul>

<h2>Summary<a id='summary'/></h2>

<p><strong>We&rsquo;ve built a hypervisor!</strong></p>

<p>It&rsquo;s far from usable in production, but <em>it is real</em>. It&rsquo;s a starting point to add further devices, exit-codes and other functionality.</p>

<p>I was surprised about the straight-forward steps to initialize and run my first VM with kvm. The register and segment initialization such as the go unsafe pointer stuff is a bit counter-intuitive for gophers, but necessary to make use of KVM. The kvm-run mechanism which return for every host invocation with an exit reason is quite clever and clear.</p>

<p>This sidequest helped me in my daily work with <a href="https://www.qemu.org/">Qemu</a> to understand the low level virtualization layer a bit better. There might be <a href="https://wiki.qemu.org/Features/Migration/Troubleshooting#Migrations_that_fail_with_an_error">some cryptic vm exception</a> which I now can more reason about.</p>

<p><a href="https://news.ycombinator.com/item?id=45051217">HN Discussion</a></p>

<h2>Appendix<a id='appendix'/></h2>

<h3>full program<a id='full-program'/></h3>

<p>Consolidating all the snippets can be anyoing since they might diverge as I rewrote the programs as I wrote this blog post.
The following standalone program boots any given image and writes io requests from port 0x42 to the screen.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;os&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;syscall&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;unsafe&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="nx">GUEST_MEMORY</span> <span class="p">=</span> <span class="mh">0x100000</span> <span class="c1">// 1Mib
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">KVM_VERSION</span>  <span class="p">=</span> <span class="mi">12</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// linux/kvm.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">KVM_BASE</span>                   <span class="p">=</span> <span class="mh">0xAE00</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_GET_API_VERSION</span>        <span class="p">=</span> <span class="nx">KVM_BASE</span> <span class="o">+</span> <span class="mh">0x00</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_CREATE_VM</span>              <span class="p">=</span> <span class="nx">KVM_BASE</span> <span class="o">+</span> <span class="mh">0x01</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_GET_VCPU_MMAP_SIZE</span>     <span class="p">=</span> <span class="nx">KVM_BASE</span> <span class="o">+</span> <span class="mh">0x04</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_CREATE_VCPU</span>            <span class="p">=</span> <span class="nx">KVM_BASE</span> <span class="o">+</span> <span class="mh">0x41</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_RUN</span>                    <span class="p">=</span> <span class="nx">KVM_BASE</span> <span class="o">+</span> <span class="mh">0x80</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_SET_USER_MEMORY_REGION</span> <span class="p">=</span> <span class="mh">0x4020ae46</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_SET_REGS</span>               <span class="p">=</span> <span class="mh">0x4090ae82</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_GET_SREGS</span>              <span class="p">=</span> <span class="mh">0x8138ae83</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_SET_SREGS</span>              <span class="p">=</span> <span class="mh">0x4138ae84</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_EXIT_REASON_HALT</span> <span class="p">=</span> <span class="mi">5</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_EXIT_REASON_IO</span>   <span class="p">=</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_IO_IN</span>  <span class="p">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">	<span class="nx">KVM_IO_OUT</span> <span class="p">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// start of kvm_run from linux/kvm.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">KVMRun</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_</span>          <span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="kt">byte</span>
</span></span><span class="line"><span class="cl">	<span class="nx">exitReason</span> <span class="kt">uint32</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_</span>          <span class="p">[</span><span class="mi">20</span><span class="p">]</span><span class="kt">byte</span>
</span></span><span class="line"><span class="cl">	<span class="nx">details</span>    <span class="p">[</span><span class="mi">256</span><span class="p">]</span><span class="kt">byte</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">KVMExitIO</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Direction</span>  <span class="kt">uint8</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Size</span>       <span class="kt">uint8</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Port</span>       <span class="kt">uint16</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Count</span>      <span class="kt">uint32</span>
</span></span><span class="line"><span class="cl">	<span class="nx">DataOffset</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// kvm_userspace_memory_region from linux/kvm.h
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">KVMUserspaceMemoryRegion</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Slot</span>          <span class="kt">uint32</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Flags</span>         <span class="kt">uint32</span>
</span></span><span class="line"><span class="cl">	<span class="nx">GuestPhysAddr</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">MemorySize</span>    <span class="kt">uint64</span> <span class="cm">/* bytes */</span>
</span></span><span class="line"><span class="cl">	<span class="nx">UserspaceAddr</span> <span class="kt">uint64</span> <span class="cm">/* start of the userspace allocated memory */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// KVM Structs (asm/kvm.h)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">KVMRegs</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">RAX</span><span class="p">,</span> <span class="nx">RBX</span><span class="p">,</span> <span class="nx">RCX</span><span class="p">,</span> <span class="nx">RDX</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">RSI</span><span class="p">,</span> <span class="nx">RDI</span><span class="p">,</span> <span class="nx">RSP</span><span class="p">,</span> <span class="nx">RBP</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">R8</span><span class="p">,</span> <span class="nx">R9</span><span class="p">,</span> <span class="nx">R10</span><span class="p">,</span> <span class="nx">R11</span>   <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">R12</span><span class="p">,</span> <span class="nx">R13</span><span class="p">,</span> <span class="nx">R14</span><span class="p">,</span> <span class="nx">R15</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">RIP</span><span class="p">,</span> <span class="nx">RFlags</span>        <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// needed for sregs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">KVMSegment</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Base</span>                           <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Limit</span>                          <span class="kt">uint32</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Selector</span>                       <span class="kt">uint16</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Tyype</span>                          <span class="kt">uint8</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Present</span><span class="p">,</span> <span class="nx">DPL</span><span class="p">,</span> <span class="nx">DB</span><span class="p">,</span> <span class="nx">S</span><span class="p">,</span> <span class="nx">L</span><span class="p">,</span> <span class="nx">G</span><span class="p">,</span> <span class="nx">AVL</span> <span class="kt">uint8</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Unusable</span>                       <span class="kt">uint8</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_</span>                              <span class="kt">uint8</span> <span class="c1">// padding
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// needed for sregs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">KVMDTable</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Base</span>  <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Limit</span> <span class="kt">uint16</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_</span>     <span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="kt">uint16</span> <span class="c1">//padding
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">KVMSRegs</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">CS</span><span class="p">,</span> <span class="nx">DS</span><span class="p">,</span> <span class="nx">ES</span><span class="p">,</span> <span class="nx">FS</span><span class="p">,</span> <span class="nx">GS</span><span class="p">,</span> <span class="nx">SS</span>  <span class="nx">KVMSegment</span>
</span></span><span class="line"><span class="cl">	<span class="nx">TR</span><span class="p">,</span> <span class="nx">LDT</span>                 <span class="nx">KVMSegment</span>
</span></span><span class="line"><span class="cl">	<span class="nx">GDT</span><span class="p">,</span> <span class="nx">IDT</span>                <span class="nx">KVMDTable</span>
</span></span><span class="line"><span class="cl">	<span class="nx">CR0</span><span class="p">,</span> <span class="nx">CR2</span><span class="p">,</span> <span class="nx">CR3</span><span class="p">,</span> <span class="nx">CR4</span><span class="p">,</span> <span class="nx">CR8</span> <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Efer</span>                    <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">ApicBase</span>                <span class="kt">uint64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">InterruptBitmap</span>         <span class="p">[</span><span class="p">(</span><span class="mi">256</span> <span class="o">+</span> <span class="mi">63</span><span class="p">)</span> <span class="o">/</span> <span class="mi">64</span><span class="p">]</span><span class="kt">uint64</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">2</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;usage: %s &lt;image&gt;\n&#34;</span><span class="p">,</span> <span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">kvm</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="s">&#34;/dev/kvm&#34;</span><span class="p">,</span> <span class="nx">os</span><span class="p">.</span><span class="nx">O_RDWR</span><span class="p">,</span> <span class="mo">0600</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;can&#39;t open kvm device: %s\n&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">defer</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Close</span><span class="p">(</span><span class="nx">kvm</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// check for stable kvm abi, needs to be &gt;=12
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">kvmVersion</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">kvm</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_GET_API_VERSION</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">			<span class="s">&#34;errror getting kvm api version %d\n&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nx">errno</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">kvmVersion</span> <span class="o">!=</span> <span class="nx">KVM_VERSION</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">			<span class="s">&#34;kvm version %d is too old, need %d or newer\n&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nx">kvmVersion</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nx">KVM_VERSION</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">vm</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">kvm</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_CREATE_VM</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">			<span class="s">&#34;errror creating vm %d\n&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nx">errno</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">defer</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Close</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="nx">vm</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">vcpu</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vm</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_CREATE_VCPU</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">			<span class="s">&#34;errror creating vcpu %d\n&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nx">errno</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">defer</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Close</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="nx">vm</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;kvm-fd=%d vm-fd=%d vcpu-fd=%d\n&#34;</span><span class="p">,</span> <span class="nx">kvm</span><span class="p">,</span> <span class="nx">vm</span><span class="p">,</span> <span class="nx">vcpu</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// map kvmrun into user-space memory
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">kvmRunSize</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">kvm</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_GET_VCPU_MMAP_SIZE</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">			<span class="s">&#34;errror getting kvm_run size %d\n&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nx">errno</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;kvm_run size: %d\n&#34;</span><span class="p">,</span> <span class="nx">kvmRunSize</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">rawKvmRun</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Mmap</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">		<span class="nb">int</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nb">int</span><span class="p">(</span><span class="nx">kvmRunSize</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">syscall</span><span class="p">.</span><span class="nx">PROT_READ</span><span class="p">|</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">PROT_WRITE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">syscall</span><span class="p">.</span><span class="nx">MAP_SHARED</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;error mapping kvm run: %s\n&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">kvmRun</span> <span class="o">:=</span> <span class="cm">/* skip *, we want a pointer! */</span> <span class="p">(</span><span class="o">*</span><span class="nx">KVMRun</span><span class="p">)</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">rawKvmRun</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// read image
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">image</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">os</span><span class="p">.</span><span class="nf">ReadFile</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;error loading image: %s\n&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// allocate guest memory
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">guestMemory</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Mmap</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">		<span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="c1">// ignored because of MAP_ANONYMOUS
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">GUEST_MEMORY</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">syscall</span><span class="p">.</span><span class="nx">PROT_READ</span><span class="p">|</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">PROT_WRITE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">syscall</span><span class="p">.</span><span class="nx">MAP_ANONYMOUS</span><span class="p">|</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">MAP_PRIVATE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;error allocating guest memory: %s\n&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;image: %x\n&#34;</span><span class="p">,</span> <span class="nx">image</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// copy embeded image
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nb">copy</span><span class="p">(</span><span class="nx">guestMemory</span><span class="p">,</span> <span class="nx">image</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">memoryRegion</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">KVMUserspaceMemoryRegion</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">Slot</span><span class="p">:</span>          <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">Flags</span><span class="p">:</span>         <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">GuestPhysAddr</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">MemorySize</span><span class="p">:</span>    <span class="nb">uint64</span><span class="p">(</span><span class="nx">GUEST_MEMORY</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">UserspaceAddr</span><span class="p">:</span> <span class="nb">uint64</span><span class="p">(</span><span class="nb">uintptr</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">guestMemory</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">)</span><span class="p">)</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vm</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_SET_USER_MEMORY_REGION</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="nx">memoryRegion</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;error setting memory region: %s\n&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">registers</span> <span class="o">:=</span> <span class="nx">KVMRegs</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">RIP</span><span class="p">:</span>    <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">RFlags</span><span class="p">:</span> <span class="mh">0x2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_SET_REGS</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">registers</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;KVM_SET_REGS: %s\n&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// get initial state of regs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kd">var</span> <span class="nx">sregs</span> <span class="nx">KVMSRegs</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_GET_SREGS</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">sregs</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;KVM_GET_SREGS: %s\n&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">sregs</span><span class="p">.</span><span class="nx">CS</span><span class="p">.</span><span class="nx">Base</span> <span class="p">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">	<span class="nx">sregs</span><span class="p">.</span><span class="nx">CS</span><span class="p">.</span><span class="nx">Selector</span> <span class="p">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_SET_SREGS</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">sregs</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;KVM_SET_REGS: %s\n&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">_</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">errno</span> <span class="p">=</span> <span class="nx">syscall</span><span class="p">.</span><span class="nf">Syscall</span><span class="p">(</span><span class="nx">syscall</span><span class="p">.</span><span class="nx">SYS_IOCTL</span><span class="p">,</span> <span class="nb">uintptr</span><span class="p">(</span><span class="nx">vcpu</span><span class="p">)</span><span class="p">,</span> <span class="nx">KVM_RUN</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="nx">errno</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;KVM_RUN: %s\n&#34;</span><span class="p">,</span> <span class="nx">errno</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="k">switch</span> <span class="nx">kvmRun</span><span class="p">.</span><span class="nx">exitReason</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">case</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">			<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;sometimes things get complicated&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span>
</span></span><span class="line"><span class="cl">		<span class="k">case</span> <span class="nx">KVM_EXIT_REASON_HALT</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span>
</span></span><span class="line"><span class="cl">		<span class="k">case</span> <span class="nx">KVM_EXIT_REASON_IO</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">			<span class="nx">ioDetails</span> <span class="o">:=</span> <span class="p">(</span><span class="o">*</span><span class="nx">KVMExitIO</span><span class="p">)</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">kvmRun</span><span class="p">.</span><span class="nx">details</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nx">start</span> <span class="o">:=</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">[</span><span class="p">]</span><span class="kt">byte</span><span class="p">)</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">kvmRun</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="nx">ioDetails</span><span class="p">.</span><span class="nx">Direction</span> <span class="o">==</span> <span class="nx">KVM_IO_OUT</span> <span class="o">&amp;&amp;</span> <span class="nx">ioDetails</span><span class="p">.</span><span class="nx">Port</span> <span class="o">==</span> <span class="mh">0x42</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nb">string</span><span class="p">(</span><span class="nx">start</span><span class="p">[</span><span class="nx">ioDetails</span><span class="p">.</span><span class="nx">DataOffset</span><span class="p">]</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">			<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;unhandeled exit reason&#34;</span><span class="p">,</span> <span class="nx">kvmRun</span><span class="p">.</span><span class="nx">exitReason</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<h3>ioctl helper<a id='ioctl-helper'/></h3>

<p>The ioctl logic to define a kvm command is a bit hard to read. I just ported it to go without reason about it much:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_NRBITS</span>   <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_TYPEBITS</span> <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_SIZEBITS</span> <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mi">14</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_DIRBITS</span>  <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_NRMASK</span>   <span class="p">=</span> <span class="p">(</span><span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_NRBITS</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_TYPEMASK</span> <span class="p">=</span> <span class="p">(</span><span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_TYPEBITS</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_SIZEMASK</span> <span class="p">=</span> <span class="p">(</span><span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_SIZEBITS</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_DIRMASK</span>  <span class="p">=</span> <span class="p">(</span><span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_DIRBITS</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_NRSHIFT</span>   <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_TYPESHIFT</span> <span class="p">=</span> <span class="p">(</span><span class="nx">_IOC_NRSHIFT</span> <span class="o">+</span> <span class="nx">_IOC_NRBITS</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_SIZESHIFT</span> <span class="p">=</span> <span class="p">(</span><span class="nx">_IOC_TYPESHIFT</span> <span class="o">+</span> <span class="nx">_IOC_TYPEBITS</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_DIRSHIFT</span>  <span class="p">=</span> <span class="p">(</span><span class="nx">_IOC_SIZESHIFT</span> <span class="o">+</span> <span class="nx">_IOC_SIZEBITS</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_NONE</span>  <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_WRITE</span> <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_IOC_READ</span>  <span class="p">=</span> <span class="nb">uintptr</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_IOC</span><span class="p">(</span><span class="nx">dir</span><span class="p">,</span> <span class="nx">tyype</span><span class="p">,</span> <span class="nx">nr</span><span class="p">,</span> <span class="nx">size</span> <span class="kt">uintptr</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="p">(</span><span class="p">(</span><span class="p">(</span><span class="nx">dir</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_DIRSHIFT</span><span class="p">)</span> <span class="p">|</span>
</span></span><span class="line"><span class="cl">		<span class="p">(</span><span class="p">(</span><span class="nx">tyype</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_TYPESHIFT</span><span class="p">)</span> <span class="p">|</span>
</span></span><span class="line"><span class="cl">		<span class="p">(</span><span class="p">(</span><span class="nx">nr</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_NRSHIFT</span><span class="p">)</span> <span class="p">|</span>
</span></span><span class="line"><span class="cl">		<span class="p">(</span><span class="p">(</span><span class="nx">size</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_SIZESHIFT</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_IO</span><span class="p">(</span><span class="nx">tyype</span><span class="p">,</span> <span class="nx">nr</span> <span class="kt">uintptr</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nf">_IOC</span><span class="p">(</span><span class="nx">_IOC_NONE</span><span class="p">,</span> <span class="p">(</span><span class="nx">tyype</span><span class="p">)</span><span class="p">,</span> <span class="p">(</span><span class="nx">nr</span><span class="p">)</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_IOR</span><span class="p">(</span><span class="nx">tyype</span><span class="p">,</span> <span class="nx">nr</span><span class="p">,</span> <span class="nx">size</span> <span class="kt">uintptr</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nf">_IOC</span><span class="p">(</span><span class="nx">_IOC_READ</span><span class="p">,</span> <span class="p">(</span><span class="nx">tyype</span><span class="p">)</span><span class="p">,</span> <span class="p">(</span><span class="nx">nr</span><span class="p">)</span><span class="p">,</span> <span class="nx">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_IOW</span><span class="p">(</span><span class="nx">tyype</span><span class="p">,</span> <span class="nx">nr</span><span class="p">,</span> <span class="nx">size</span> <span class="kt">uintptr</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nf">_IOC</span><span class="p">(</span><span class="nx">_IOC_WRITE</span><span class="p">,</span> <span class="p">(</span><span class="nx">tyype</span><span class="p">)</span><span class="p">,</span> <span class="p">(</span><span class="nx">nr</span><span class="p">)</span><span class="p">,</span> <span class="nx">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_IOWR</span><span class="p">(</span><span class="nx">tyype</span><span class="p">,</span> <span class="nx">nr</span><span class="p">,</span> <span class="nx">size</span> <span class="kt">uintptr</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nf">_IOC</span><span class="p">(</span><span class="nx">_IOC_READ</span><span class="p">|</span><span class="nx">_IOC_WRITE</span><span class="p">,</span> <span class="p">(</span><span class="nx">tyype</span><span class="p">)</span><span class="p">,</span> <span class="p">(</span><span class="nx">nr</span><span class="p">)</span><span class="p">,</span> <span class="nx">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_IOC_DIR</span><span class="p">(</span><span class="nx">nr</span> <span class="kt">uintptr</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="p">(</span><span class="p">(</span><span class="p">(</span><span class="nx">nr</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="nx">_IOC_DIRSHIFT</span><span class="p">)</span> <span class="o">&amp;</span> <span class="nx">_IOC_DIRMASK</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_IOC_TYPE</span><span class="p">(</span><span class="nx">nr</span> <span class="kt">uintptr</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="p">(</span><span class="p">(</span><span class="p">(</span><span class="nx">nr</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="nx">_IOC_TYPESHIFT</span><span class="p">)</span> <span class="o">&amp;</span> <span class="nx">_IOC_TYPEMASK</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_IOC_NR</span><span class="p">(</span><span class="nx">nr</span> <span class="kt">uintptr</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="p">(</span><span class="p">(</span><span class="p">(</span><span class="nx">nr</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="nx">_IOC_NRSHIFT</span><span class="p">)</span> <span class="o">&amp;</span> <span class="nx">_IOC_NRMASK</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_IOC_SIZE</span><span class="p">(</span><span class="nx">nr</span> <span class="kt">uintptr</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="p">(</span><span class="p">(</span><span class="p">(</span><span class="nx">nr</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="nx">_IOC_SIZESHIFT</span><span class="p">)</span> <span class="o">&amp;</span> <span class="nx">_IOC_SIZEMASK</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">IOC_IN</span><span class="p">(</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="p">(</span><span class="nx">_IOC_WRITE</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_DIRSHIFT</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">IOC_OUT</span><span class="p">(</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="p">(</span><span class="nx">_IOC_READ</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_DIRSHIFT</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">IOC_INOUT</span><span class="p">(</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="p">(</span><span class="p">(</span><span class="nx">_IOC_WRITE</span> <span class="p">|</span> <span class="nx">_IOC_READ</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_DIRSHIFT</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">IOCSIZE_MASK</span><span class="p">(</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="p">(</span><span class="nx">_IOC_SIZEMASK</span> <span class="o">&lt;&lt;</span> <span class="nx">_IOC_SIZESHIFT</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">IOCSIZE_SHIFT</span><span class="p">(</span><span class="p">)</span> <span class="kt">uintptr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="p">(</span><span class="nx">_IOC_SIZESHIFT</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<h2>References<a id='references'/></h2>

<ul>
<li><a href="https://lwn.net/Articles/963718/">KVM: x86/PVM: Introduce a new hypervisor</a></li>
<li><a href="https://lwn.net/Articles/658511/">LWN: Using the KVM API</a></li>
<li><a href="https://david942j.blogspot.com/2018/10/note-learning-kvm-implement-your-own.html">[Note] Learning KVM - implement your own kernel </a></li>
<li><a href="https://github.com/google/novm">Google&rsquo;s archived novm</a></li>
<li><a href="https://iovec.net/2024-01-29">https://iovec.net/2024-01-29</a></li>
<li><a href="https://zserge.com/posts/kvm/">https://zserge.com/posts/kvm/</a></li>
<li><a href="https://github.com/flouthoc/wiser">https://github.com/flouthoc/wiser</a></li>
<li><a href="https://yeet.cx/blog/you-are-the-bios-now">https://yeet.cx/blog/you-are-the-bios-now</a></li>
</ul>

<h3>Glossary<a id='glossary'/></h3>

<ul>
<li>VM: virtual machine, isolated (para)virtualized hardware platform, guest behaves like on real hardware</li>
<li>hypervisor: Manages and operates vitual machines</li>
<li>guest: the operating system inside a virtual machine</li>
<li>host/bare-metal: physical machine</li>
<li>vcpu: virtual cpu</li>
<li>KVM API: linux&rsquo;s <a href="https://lwn.net/Articles/658511/">Kernel Virtual Machine API</a> for paravirtualizing systems</li>
</ul>

<p><small style="color:rgba(0,0,0,0)">+rv=tch1b0,ai</small></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Golang is currently main main language. Previously: VisualBasic, C, PHP, C#/Python, Python, Ruby/Golang</li>

<li id="fn:2">Unless they have <a href="https://www.linux-kvm.org/page/Nested_Guests">nested virtualization</a> enabled. This is unlikely while live migration of a VM between hosts won&rsquo;t work properly.</li>

<li id="fn:arm">KVM should also support aarch64 (arm) but there might be differences. At least the bootloader and register initialization is probably different.</li>

<li id="fn:3"><a href="https://lwn.net/Articles/658511/">LWN: Using the KVM API</a></li>

<li id="fn:4">Should be equal as the fd&rsquo;s are assigned sequentially and first three fd&rsquo;s of a usual linux program are <code>0=stdin,1=stdout,2=stderr</code>.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Thu, 28 Aug 2025 06:00:00 +0200</pubDate>
    </item>
    <item>
      <title>Stickers on my laptop billboard</title>
      <link>https://evilcookie.de/stickers-on-my-laptop-billboard.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Stickers on my laptop billboard</h1>

<p><img src="stickers-on-my-laptop-billboard_billboard.jpg"/>
<small style="color:gray">Laptop lid with stickers.</small></p>

<p>It has become quite normal to cover the laptop lid with random stickers. You can get such sticker at any conference en masse.
It&rsquo;s an expression of &ldquo;Hey, look at my stack!&rdquo; or other stuff that one cares about.</p>

<p>For the sticker connoisseur that I am, I choose carefully which ones get the privilege to cover my laptop <del>lid</del> billboard.
Now I want to share the current state of said billboard and what it means (for me).</p>

<p>From top to bottom, from left to right:</p>

<ol>
<li><a href="https://www.mozilla.org/de/firefox">Mozilla Firefox</a>, Open-Source Web Browser: Default browser for ages now. The sticker was handed over by an actual Mozilla employee<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. If you look closely, the red thinkpad LED shines through the foxes eye.</li>
<li>Atomuhr? Nein Danke ( &ldquo;Atomic clock? No, thanks&rdquo;): A homage to the original <a href="https://de.wikipedia.org/wiki/Atomkraft%3F_Nein_danke">Atomkraft? Nein Danke</a> (Nuclear power? No thanks) movement against the use nuclear power. It plays with the double meaning of the German word &ldquo;Atom&rdquo;, which can mean both &ldquo;atom&rdquo; and &ldquo;nuclear&rdquo;.</li>
<li><a href="https://github.com/Glow-Project/">Pour Entertainment</a>: Name of my brothers and my game studio for all the <a href="https://evilc00kie.itch.io/">Godot Wild Jam Games</a>.</li>
<li>Yes we curl: Homage (I guess?) to the political claim &ldquo;Yes we can!&rdquo; from Barack Obamas campaign for US president 2008. Instead of Obama it features <a href="https://curl.se/">curl&rsquo;s</a> inventor <a href="https://daniel.haxx.se/">Daniel Stenberg</a> next to the curl logo. In times of hype-driven-development and ever changing stacks, I find it quite refreshing that Daniel works on this successful project for almost 30 years now.</li>
<li>Praemium: Hard to see because of the transparent text. It&rsquo;s a swabian written phonetics of &ldquo;Premium&rdquo;. It reminds me of my homeland: <a href="https://www.thelaend.de/en/discover-the-laend/">&ldquo;The Länd&rdquo;</a>.</li>
<li>Ubuntu text next to debian logo: Just for rage baiting OS purists :D</li>
<li>Tja: German word for summing up a loss or resignation. It&rsquo;s hard to describe but quite unique and expressive.</li>
<li><a href="https://en.wikipedia.org/wiki/Tux_(mascot)">Tux</a>: The linux penguin-duck that sneaks onto the lid.</li>
<li>Mozarella: Homage to the original Mozilla logo.<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></li>
<li>EU Flag: Because it only works together :)</li>
<li><a href="https://fedoraproject.org/">Fedora</a>: Because I don&rsquo;t just want to os rage bait on my lid, this is actually the OS I use.</li>
<li><a href="gitlab.com">GitLab</a>: I really enjoy working with GitLab as a collaborative, repository-centered developer platform. Its built-in CI/CD helps me a lot building reliable software.</li>
</ol>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Shout outs to <a href="https://auch.cool">flipez</a></li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 30 Jun 2025 16:17:57 +0200</pubDate>
    </item>
    <item>
      <title>Gokrazy with Raspberry Pi Zero</title>
      <link>https://evilcookie.de/gokrazy-with-raspberry-pi-zero.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Gokrazy with Raspberry Pi Zero</h1>

<p><img src="gokrazy-with-raspberry-pi-zero_monitor.jpg"/>
<small style="color:gray">Default gokrazty output.</small></p>

<p>I started my IoT journey with a Raspberry Pi 1 B and have since settled on the Arduino Pico/Esp32 so far.
Recently, someone showed me their small <a href="https://en.wikipedia.org/wiki/General-purpose_input/output">GPIO</a> code in Go and the remarkably simple CLI to build and update an image on a remote IoT device.</p>

<p>This post is a summary of the steps I did to let an LED blink with <a href="https://gokrazy.org/">gokrazy</a> and a <a href="https://www.raspberrypi.com/products/raspberry-pi-zero-2-w/">Raspberry Pi Zero 2W</a>, hence I want to do this again.</p>

<h2>Setup</h2>

<p>Let&rsquo;s set up a new gokrazy project and flash it onto the SD card.</p>

<ol>
<li>Install gokrazy cli: <code>go install github.com/gokrazy/tools/cmd/gok@main</code></li>
<li>Initialize repo, will create <code>~/gokrazy/hello</code>: <code>gok new</code></li>
<li>Goto directory and add the gpio repo: <code>gok add github.com/RaphaelPour/gpio</code></li>
<li>Replace the hostname with the ip address in config.json (in case the hostname doesn&rsquo;t get resolved properly)</li>
<li>Add Wifi Module: <code>gok add github.com/gokrazy/wifi</code> and follow <a href="https://gokrazy.org/userguide/wifi/">configuration instructions</a></li>
<li>Add your project having a <code>main.go</code> via <code>gok add ~/dev/mygokrazypkg</code> or <code>github.com/RaphaelPour/mygokrazypackage</code></li>
<li>Insert SD card and locate the device (e.g. via <code>lsblk</code>). Mine is under <code>/dev/sda</code><sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></li>
<li>Build and flash: <code>gok overwrite --full /dev/sda</code></li>
<li>Any further update: <code>gok update</code></li>
</ol>

<p>Notes:</p>

<ul>
<li>HDMI-to-MiniHDMI adapter is needed to connect a monitor to the raspi</li>
<li>Monitor output can be useful to obtain the raspi&rsquo;s IP</li>
<li>gok project is separated from any program that is running on it</li>
<li>Raspberry Pi Zero&rsquo;s wifi chip doesn&rsquo;t support 5GHz</li>
<li><a href="https://pkg.go.dev/periph.io/x/periph@v3.6.8+incompatible/host/rpi">Pinout mapping go lib</a></li>
</ul>

<h2>In-use</h2>

<p><img src="gokrazy-with-raspberry-pi-zero_output.jpg"/></p>

<p>After flashing the image properly, the raspi connects to the specified WLan and provides a website. Credentials can be obtained from the <code>gok overwrite</code> output (see above) or <code>config.json</code>. Username is <code>gokrazy</code>.</p>

<p><img src="gokrazy-with-raspberry-pi-zero_website.png"/></p>

<h2>Run own program</h2>

<p>Now I want to run my own program and do the ultimate hardware test: can it blink?</p>

<p>But first some general steps to set up a new repo with custom code:</p>

<ol>
<li>create new folder or repo (doesn&rsquo;t need to be within the gokrazy directory), <code>~/dev/gpio</code> in my case</li>
<li>add custom program with regular <code>main</code> function</li>
<li>go back to gokrazy dir and add the repo via <code>gok add &lt;url|path&gt;</code>, <code>gok add ~/dev/gpio</code> in my case</li>
<li>build image as usual, gokrazy will pull the repo and run it on boot</li>
</ol>

<h3>GPIO program</h3>

<p>The following Go program is a minimal example for letting an LED blink. It uses GPIO pin 17 and the LED stays on (and off) for 100ms. GPIO Pin and the duration can be altered in the variable section.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;log&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;time&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="s">&#34;periph.io/x/conn/v3/gpio&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;periph.io/x/conn/v3/gpio/gpioreg&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">host</span> <span class="s">&#34;periph.io/x/host/v3&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="nx">delay</span> <span class="p">=</span> <span class="mi">100</span> <span class="o">*</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Millisecond</span>
</span></span><span class="line"><span class="cl">	<span class="nx">pin</span>   <span class="p">=</span> <span class="nx">gpioreg</span><span class="p">.</span><span class="nf">ByName</span><span class="p">(</span><span class="s">&#34;GPIO17&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">host</span><span class="p">.</span><span class="nf">Init</span><span class="p">(</span><span class="p">)</span><span class="p">;</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nb">panic</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">pin</span><span class="p">.</span><span class="nf">Out</span><span class="p">(</span><span class="nx">gpio</span><span class="p">.</span><span class="nx">High</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;high&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="nx">time</span><span class="p">.</span><span class="nf">Sleep</span><span class="p">(</span><span class="nx">delay</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="nx">pin</span><span class="p">.</span><span class="nf">Out</span><span class="p">(</span><span class="nx">gpio</span><span class="p">.</span><span class="nx">Low</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;low\n&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="nx">time</span><span class="p">.</span><span class="nf">Sleep</span><span class="p">(</span><span class="nx">delay</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<ul>
<li>I&rsquo;ve connected an LED with a 220Ω resistor<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> between GPIO pin 17 and ground</li>
<li><code>gpioreg</code><sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup> provides mapping for the Raspberry Pi Zero</li>
<li>the log is useful for debugging and can be viewed via the gokrazy website</li>
</ul>

<h2>Advantages</h2>

<p>I&rsquo;ve found several advantages in contrast to my Arduino/ESP32 projects:</p>

<ul>
<li><a href="https://www.redhat.com/en/topics/linux/what-is-a-golden-image">golden images</a>: don&rsquo;t maintain a heavy distro, just replace the whole image on update</li>
<li>simple update: <a href="https://en.wikipedia.org/wiki/Over-the-air_update">OTA update</a> via <code>gok update</code></li>
<li>Go + many packages: use a well-supported and quite comfortable language along with its ecosystem for embedded use cases</li>
</ul>

<h2>Challenges</h2>

<p>In general there were some challenges on setting up the project:</p>

<ul>
<li>Soldering the pin header was a bit messy. Learning: use 320C instead of just 270 with Weler Sn99.3Cu0.6Ni0.05 solder tin or just buy a one with a pre-soldered pin header</li>
<li>The hostname doesn&rsquo;t resolve properly with my DNS. Use the ip address instead.</li>
</ul>

<h2>Impressions</h2>

<p><img src="gokrazy-with-raspberry-pi-zero_raspi.jpg"/></p>

<p><img src="gokrazy-with-raspberry-pi-zero_desk.jpg"/></p>

<h2>References</h2>

<ul>
<li><a href="https://gokrazy.org/">Official gokrazy website</a></li>
<li><a href="https://gokrazy.org/quickstart/">Official gokrazy quickstart</a></li>
<li><a href="https://gokrazy.org/userguide/wifi/">Wifi configuration guide</a></li>
<li><a href="https://pinout.xyz">General Raspberry Pi pinout</a></li>
</ul>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Because my laptop has an NVMe, the SD card gets assigned the <code>sda</code> device name.</li>

<li id="fn:2">Limit the maximal current the LED can draw  to protect it from overheating.</li>

<li id="fn:3">See <a href="https://periph.io/">periph.io</a>.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 11 Jun 2025 16:15:43 +0200</pubDate>
    </item>
    <item>
      <title>Reinvent the wheel</title>
      <link>https://evilcookie.de/reinvent-the-wheel.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Reinvent the wheel</h1>

<p><img src="reinvent-the-wheel_wheel.jpg"/>
<small style="color:gray">Detailed photo with flash from my dad&rsquo;s mountainbike tire.</small></p>

<blockquote>
<p>Write more &ldquo;useless&rdquo; software<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></p>
</blockquote>

<p>was the claim that inspired me to think about clones and yet-anothers<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">2</a></sup>.</p>

<p>Reinventing the wheel is often said to be a waste of knowledge and time. If someone solved the problem before, why do it yourself? It&rsquo;s easier to use dependencies especially when they receive periodic contributions.</p>

<p>Well, this is true&hellip; until it&rsquo;s not.</p>

<h3>Contents</h3>

<ul>
<li><a href="#why">Why?</a>

<ul>
<li><a href="#learning">Learning</a></li>
<li><a href="#new-concepts">Try out new concepts</a></li>
<li><a href="#diversity">Diversity</a></li>
<li><a href="#redundancy">Redundancy</a></li>
<li><a href="#motivation">Reduced motivation lack</a></li>
</ul></li>
<li><a href="#why-not">Why not</a>

<ul>
<li><a href="#maintenance">Maintenance</a></li>
<li><a href="#hacking">Hacking over reinventing</a></li>
</ul></li>
<li><a href="#my-reinvented-wheels">My reinvented wheels</a>

<ul>
<li><a href="#blogctl">Blogctl</a></li>
<li><a href="#lsystems">L-Systems</a></li>
<li><a href="#femto">Femto</a></li>
<li><a href="#md2">MD2</a></li>
<li><a href="#osrelease">Osrelease</a></li>
<li><a href="#life">Game of Life</a></li>
<li><a href="#kvm">KVM Hypervisor</a></li>
</ul></li>
<li><a href="#vision">Vision</a></li>
</ul>

<h2>Why?<a id='why'/></h2>

<h3>Learning<a id='learning'/></h3>

<p>Ever wondered how a json parser, regex, openssl, a webserver and whatsoever worked? Implement it and learn its functionality as you go.</p>

<h3>Try out new concepts<a id='new-concepts'/></h3>

<p>Saw this new concept on hacker news or your new favorite O&rsquo;Reilly book and want to test it? Well, then use what&rsquo;s already there
and reimplement it with the new concept. Both solutions can then be compared with each other. If they fulfill the same specification,
the tests might even be usable for benchmarking.</p>

<h3>Diversity<a id='diversity'/></h3>

<p>Although the specification among several projects is equal and they can be used as drop-ins, their implementation differences can
be worth weighting the pros and cons over another. Different languages, paradigms (OOP, functional, logical) or optimizations (SIMD, OpenCL/Cuda, &hellip;)
can lead to significant performance differences.</p>

<h3>Redundancy<a id='redundancy'/></h3>

<p>Even if it&rsquo;s the same as some other software, redundancy can become very handy when the community behind one
project breaks apart, licenses change or it just gets abandoned<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">3</a></sup>.</p>

<h3>Reduced lack of motivation<a id='motivation'/></h3>

<p>Working on a problem that has already been solved makes it easier to shift the focus away from
what-to-implement to how-to-implement. It&rsquo;s not &ldquo;Do I do the right thing?&rdquo; but &ldquo;Do I do the thing right?&rdquo;. The difference may
seem subtle, but at least for me, having a known-to-work specification helps me focus on progressing.</p>

<h2>Why not<a id='why-not'/></h2>

<p>Of course there are also some arguments against it.</p>

<h3>Maintenance<a id='maintenance'/></h3>

<p>While it&rsquo;s educational and fun to create something new, once it&rsquo;s used in production by yourself or others,
maintenance should be considered every now and then, which can get time consuming.</p>

<h3>Hacking over reinventing<a id='hacking'/></h3>

<p>Building something from scratch often comes with a bunch of surrounding code that needs to be implemented before
coming to the relevant core.</p>

<p>Another approach could be to use something existing and hack it instead. For example fork the <a href="https://github.com/goccy/go-yaml">go-yaml</a> repo and change or add some
parser rules like merging a yaml anchor from another file.</p>

<h2>My reinvented wheels<a id='my-reinvented-wheels'/></h2>

<h3>blogctl<a id='blogctl'/></h3>

<p><a href="https://github.com/RaphaelPour/blogctl">Blogctl</a> is the static-site generator for <code>$this</code> blog. There are tons of such blog generators out there, like <a href="https://gohugo.io/">Hugo</a> or <a href="https://jekyllrb.com/">Jekyll</a>.</p>

<p>I wanted to have a project that progresses along with me having my tempo. In the beginning there was just text. Then I&rsquo;ve added an <a href="https://evilcookie.de/blog-update-rss-feed.html">RSS feed</a>, <a href="https://evilcookie.de/blog-update-image-support.html">images</a>, <a href="https://evilcookie.de/blog-update---navigation.html">navigation</a> and <a href="https://evilcookie.de/blog-update-v030.html">syntax highlighting</a>. Not only is blogctl my shot on a static site generator, it&rsquo;s an essential part of the blog and its aesthetic.</p>

<h3>L-Systems<a id='lsystems'/></h3>

<p><a href="https://github.com/RaphaelPour/lsystems">L-Systems</a> is an implementation of the formal <a href="https://en.wikipedia.org/wiki/L-system">L-System</a> hosted at <a href="https://lsystems.raphaelpour.de/">lsystem.raphaelpour.de</a>. It was originally invented by <a href="https://en.wikipedia.org/wiki/Aristid_Lindenmayer">A. Lindenmayer</a> for modelling plants, but it&rsquo;s so versatile that it also can create pretty fractals. It&rsquo;s featured along with other modeling techniques within the book <a href="https://algorithmicbotany.org/papers/abop/abop.pdf">The algorithmic beauty of plants</a>.</p>

<h3>femto<a id='femto'/></h3>

<p><a href="https://github.com/RaphaelPour/femto">Femto</a> is my shot on <a href="https://antirez.com">Antirez&rsquo;s</a> command line editor <a href="https://github.com/antirez/kilo">kilo</a>.</p>

<h3>md2<a id='md2'/></h3>

<p>In my cs studies, I reimplemented <a href="https://github.com/RaphaelPour/md2">MD2</a> in C. Although it already was deprecated/broken back then, it gave a
simple insight into the mechanics of a hashing algorithm.</p>

<h3>osrelease<a id='osrelease'/></h3>

<p><a href="https://github.com/RaphaelPour/osrelease">Osrelease</a> is my go library to access the current OS release with a comparable type.</p>

<h3>Game of life<a id='life'/></h3>

<p><a href="https://github.com/RaphaelPour/life">Life</a> is an implementation of  <a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Conway&rsquo;s game of life</a> hosted at <a href="https://life.raphaelpour.de/">life.raphaelpour.de</a>.</p>

<h3>KVM Hypervisor<a id='kvm'/></h3>

<p>Booting a very trivial bootloader within a virtual machine is surprisingly approachable using KVM, as described in my <a href="https://evilcookie.de/lets-build-an-hypervisor-with-kvm.html">corresponding blog post</a>.</p>

<h2>Vision<a id='vision'/></h2>

<p>There are a few projects I want to do sometime in the future:</p>

<ul>
<li>regex parser</li>
<li><a href="https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form">BNF parser</a></li>
<li>list interpreter (like <a href="https://www.buildyourownlisp.com/">Build your own lisp</a>)</li>
<li>graphic engine with shader (like OpenGL with GLSL)</li>
<li>config format (ZML is my current favorite name)</li>
<li>implement an RFC</li>
<li>essential network stack</li>
<li>VST/AudioUnit</li>
</ul>

<p><small style="color:rgba(0,0,0,0)">+rv=ai</small></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1"><a href="https://chemnitzer.linux-tage.de/2024/media/programm/folien/112.pdf">RocketLang - Mein eigener kleiner BER</a> from Chemnitzer Linux-Tage 2024. Shout out to <a href="auch.cool">Flipez</a>!</li>

<li id="fn:3"><a href="https://en.wikipedia.org/wiki/YAML">Yet-Another-Markup-Language</a>, <a href="https://en.wikipedia.org/wiki/Yacc">Yet-Another-Compiler-Compiler</a></li>

<li id="fn:2">I&rsquo;m looking at your <a href="https://opensearch.org/">Opensearch</a> (fork of <a href="https://www.elastic.co/elasticsearch">Elasticsearch</a>) and <a href="https://valkey.io/">Valkey</a> (fork of <a href="redis.io">redis</a>). Both forks were made due to a license change from an open source to a closed source one.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Sat, 17 May 2025 08:31:29 +0200</pubDate>
    </item>
    <item>
      <title>Analog Oscilloscope e2e tests</title>
      <link>https://evilcookie.de/analog-oscilloscope-e2e-tests.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Analog Oscilloscope e2e tests</h1>

<p>Lately I fulfilled a long-forgotten dream and became owner of an analog oscilloscope. One that you probably
had in your physics class back then. A <a href="https://www.radiomuseum.org/r/hameg_oszilloskop_hm203_7.html">Hameg HM 203-7</a>:</p>

<p><img src="analog-oscilloscope-e2e-tests_osc_total.jpg"/></p>

<p>This blog post combines software testing perspectives with electronics. I also want to describe my ux/ui observations as the oscilloscope is analog only.</p>

<p>Disclaimer: I&rsquo;m not a certified electronics technician. I bought the device from a IMO trustworthy German company stated to be in second-hand (but not defect) condition.</p>

<h3>Content</h3>

<ul>
<li><a href="#motivation">Motivation</a></li>
<li><a href="#testing">Testing</a>

<ul>
<li><a href="#cathode-tube">Cathode tube</a></li>
<li><a href="#smoke-tests">Smoke tests</a></li>
<li><a href="#channel-tests">Channel</a></li>
<li><a href="#external">External input</a></li>
<li><a href="#result">Result</a></li>
</ul></li>
<li><a href="#ui-ux">UI/UX</a></li>
<li><a href="#summary">Summary</a></li>
<li><a href="#vision">Vision</a></li>
</ul>

<h2>Motivation <a id='motivation'/></h2>

<p>I have a quite respectable collection of synthesizer and eurorack modules to discover sound engineering on a basic level. Not only does the cathode tube screen looks pretty cool with its retro look, it also helps to investigate sound design and its issues.</p>

<p><img src="analog-oscilloscope-e2e-tests_eurorack.jpg"/>
<small style="color:gray">Some wild eurorack appears.</small></p>

<p>Well, and I also want to hook it up on other random stuff. Like my DAW or some circuitry.</p>

<p>Testing the oscilloscope like software came intuitively in my mind when I was about to involve my little brother in testing. Rather than just quickly plug it in and play around, I thought it would be educational if I specify my testing strategy, step by step.</p>

<h2>Testing<a id='testing'/></h2>

<p>As this is a really old model from 1985 having a cathode tube, I wasn&rsquo;t quite sure if this just catches fire on start up.
So I came up with a list of basic <a href="https://microsoft.github.io/code-with-engineering-playbook/automated-testing/e2e-testing/">e2e tests</a> to quickly get a bigger picture of its operational condition.</p>

<p>End-to-end (e2e) tests are used for systems acting like a <a href="https://en.wikipedia.org/wiki/Black-box_testing">black box</a>. This means that they can only be controlled and observed from the outside perspective. They&rsquo;re the outermost ones that on one side can quickly verify that a system works properly but on the other side mostly don&rsquo;t tell much about a failure<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">1</a></sup>.</p>

<p>I also use the Given-When-Then Syntax from <a href="https://en.wikipedia.org/wiki/Behavior-driven_development">behavior driven development</a>.</p>

<h3>Cathode tube <a id='cathode-tube'/></h3>

<p>The screen of the device consists of a <a href="https://en.wikipedia.org/wiki/Cathode-ray_tube">cathode-ray tube</a>, which is basically a glass tube under pressure.</p>

<ul>
<li>Test 1 - glass sound:

<ul>
<li>when: the device gets moved a bit</li>
<li>then: no sound of shattered glass or other loose material should be audible</li>
</ul></li>
</ul>

<h3>Smoke tests <a id='smoke-tests'/></h3>

<p>Those tests are as simple as dangerous but provide essential insight if the circuitry could do any harm<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">2</a></sup>:</p>

<blockquote>
<p>[&hellip;] You plug in a new board and turn on the power. If you see smoke coming from the board, turn off the power.
You don&rsquo;t have to do any more testing.</p>
</blockquote>

<ul>
<li>Test 2 - power supply:

<ul>
<li>given: turned off device</li>
<li>when: the power supply gets connected</li>
<li>then: no smoke, no significant smell, no significant noise (transformer is ok)</li>
</ul></li>
<li>Test 3 - power supply:

<ul>
<li>given: device with plugged in power supply</li>
<li>when: the device gets turned on</li>
<li>then: power led should turn on, something gets drawn on the screen and again: no smoke, no smell, no noise</li>
</ul></li>
</ul>

<p>Most relieving observation after the third test: The screen lights up and a moving dot appears \o/</p>

<p><img src="analog-oscilloscope-e2e-tests_first_startup.jpg"/>
<small style="color:gray">First startup: power button lights up and a continuous line is drawn to the screen.</small></p>

<h3>Channel<a id='channel'/></h3>

<p>Dials and switches can get worn out over time, especially after 40 years. Based on the article description of the oscilloscope, the seller was closing a workshop and
liquidated some equipment. So it might have been in heavy use.</p>

<ul>
<li>Test 4 - calibration signal:

<ul>
<li>given: turned on device</li>
<li>when: calibration pin gets connected to channel one</li>
<li>then: a noticeable change on the screen should&rsquo;ve happened</li>
</ul></li>
<li>Test 5 - scaling:

<ul>
<li>given: channel one is connected to one of the calibration pins</li>
<li>when: the time-division and volts-division knobs get turned</li>
<li>then: the visualization on the screen should adjust accordingly</li>
</ul></li>
<li>Test 6 - offset:

<ul>
<li>when: x-offset and y-offset gets turned</li>
<li>then: the visualized signal should move accordingly on the screen</li>
</ul></li>
</ul>

<p><img src="analog-oscilloscope-e2e-tests_test_signal.jpg"/>
<small style="color:gray">Screenshot of the 0.2V calibration signal</small></p>

<p>Repeat the process for channel two.</p>

<h3>External input test<a id='external'/></h3>

<p>I hooked up my <a href="https://en.wikipedia.org/wiki/Volca_Bass">Korg Volca Bass</a><sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup> to the channel one and played around a bit.</p>

<ul>
<li>Test 7 - external input:

<ul>
<li>given: external input is connected to channel one</li>
<li>given: external input generates some signal</li>
<li>then: some signal should be visualized</li>
</ul></li>
</ul>

<p><img src="analog-oscilloscope-e2e-tests_osc.gif"/>
<small style="color:gray">Playing around with the volca bass&rsquo;s Filter and Resonance</small></p>

<p><img src="analog-oscilloscope-e2e-tests_volcabass.jpg"/></p>

<h3>Result<a id='result'/></h3>

<p>Although the oscilloscope is 40 years old, it works perfectly well for its condition and my needs. It passed all the tests. Some buttons get stuck when pressed, but can be freed by gently pulling them with pliers. I had expected some capacitors to be blown after such a long time. Maybe some are blown as I didn&rsquo;t verify whether the visualized and actual voltage matched, but that&rsquo;s not interesting for me.</p>

<h3>UI/UX<a id='ui-ux'/></h3>

<p><img src="analog-oscilloscope-e2e-tests_ui.jpg"/>
<small style="color:gray">A closer look to the oscilloscope&rsquo;s interface.</small></p>

<p>The screen response is immediate. Dialing and pressing a button gives immediate haptic and audible feedback. Each function has its own dial or button. No menus, no modes, no shift-key that changes the purpose of a control. I wasn&rsquo;t aware of this until I got my hands on this oscilloscope, but I really love this 1:1 mapping between functionality and controls<sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup>. Especially when fiddling around with sound and music, a fast feedback loop without multiple layers is key for me.</p>

<p>I wonder how such design could be adapted to software.</p>

<h2>Summary<a id='summary'/></h2>

<p>The software testing approach for verifying this old piece of hardware worked surprisingly well. The test concept made formulating test scenarios straightforward. I could have simply plugged in the device and played around but taking a step back and formulating premises and their expected outcomes made the discovery of this analog technology even more fun.</p>

<p>The look and feel, such as the 1:1 control to function mapping inspired me to think more about symbiosis between analog and digital UI/UX principles.</p>

<h2>Vision<a id='vision'/></h2>

<ul>
<li>discover more 1:1 interfaces and how they affect workflows</li>
<li>connect to sound interface while producing with DAW</li>
<li>playing around with <a href="https://en.wikipedia.org/wiki/Lissajous_curve">Lissajous curves</a></li>
<li>rendering some cool stuff onto it via microcontroller/raspi like this <a href="https://www.youtube.com/watch?v=OU16lIx_pC8">DOOM demo</a></li>
</ul>

<p><small style="color:rgba(0,0,0,0)">+rv=ai</small></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:2"><p>In comparison to a unit test withing software development that checks the most atomic unit the code is organized which
  is a method or function in most cases.</p></li>

<li id="fn:1"><a href="https://en.wikipedia.org/wiki/Smoke_testing_(electrical">https://en.wikipedia.org/wiki/Smoke_testing_(electrical</a>)</li>

<li id="fn:3">My first ever hardware synth.</li>

<li id="fn:4">Likewise to my second hardware synth I ever got, the <a href="https://en.wikipedia.org/wiki/Korg_MS-20">Korg MS 20 Mini</a>.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 07 May 2025 21:29:35 +0200</pubDate>
    </item>
    <item>
      <title>Chemnitzer Linuxtage 2025</title>
      <link>https://evilcookie.de/chemnitzer-linuxtage-2025.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Chemnitzer Linuxtage 2025</h1>

<p><img src="chemnitzer-linuxtage-2025_clt.png"/></p>

<p>I&rsquo;ve attended the <a href="https://chemnitzer.linux-tage.de/2025/en/">Chemnitzer Linuxtage</a> for the second time<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>.</p>

<p>You want it, you get it. Some data:</p>

<ul>
<li>date: 22.03.2025 + 23.03.2025</li>
<li>location: <a href="https://www.tu-chemnitz.de/">TU Chemnitz</a></li>
<li>Chemnitz is the <a href="https://chemnitz2025.de/en/">european capital of culture 2025</a></li>
</ul>

<h2>nftables<a id="nftables"/></h2>

<p>This <a href="https://media.ccc.de/v/clt25-224-einfuhrung-in-nftables">talk</a> gave essential insight into declarative firewalls with <a href="https://www.nftables.org/">nftable</a> and filled some blank spaces in my linux administration knowledge.</p>

<ul>
<li>Hook: interception of the <a href="https://xinux.net/index.php/Nftables_Hooks">fixed filter graph</a> where custom chains can be specified</li>
<li>Chain: list of rules to decide if a packet gets dropped or passed to the next hook</li>
<li>Rule: applies condition onto a packets metadata resulting in a drop, accept or pass to the next rule. Rule to allow some basic tcp ports: <code>tcp dport { 22, 80, 443} accept</code></li>
</ul>

<p>Beside tcp port allowance rules can access the packets ipv4, ipv6, arp, ethernet, tcp, udp header to make decisions. Also stateful firewall scenarios like NAT using contrack is possible.</p>

<h2>initramfs<a id="initramfs"/></h2>

<p>The <a href="https://media.ccc.de/v/clt25-248-was-ist-eigentlich-dieses-initramfs">talk</a> described the process between a bootloader and an up and running linux operating system.
Something need to actually initialize the kernel including:</p>

<ul>
<li>mount disks</li>
<li>disk decryption</li>
<li>assemble raid</li>
</ul>

<p>It consists of an archive that get loaded and executed by the bootloader. The archive itself is built by the operating system manually or on system update. Building
the archive is also often the slow part at the and of any system update.</p>

<p><img src="chemnitzer-linuxtage-2025_initramfs.png"/></p>

<p>Initially the <a href="https://de.wikipedia.org/wiki/Initrd">initrd</a> (short for init ram disk) took care of this, but got reworked to initramfs<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>.</p>

<h2>Others</h2>

<p>Some other great talks I enoyed:</p>

<ul>
<li><a href="https://media.ccc.de/v/clt25-164-von-pxelinux-zu-ipxe-im-rechenzentrum">from pxe to ipxe in a data center</a>: Tan described the chances and challenges of using ipxe on a diverse server hardware landscape like in our data centers.</li>
<li><a href="https://media.ccc.de/v/clt25-134-so-funktioniert-der-linux-storage-stack">linux storage stack</a>: Shed light into the storage stack of linux including the device mapper mechanic.</li>
</ul>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Third time, if you count my talk at the virtual conference in <a href="https://evilcookie.de/clt-2022---storage-migration-schnell-und-einfach.html">2022</a>.</li>

<li id="fn:2">See <a href="https://lwn.net/Articles/191004/">lwn.net - initramfs and where user space truly begins</a></li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Sat, 05 Apr 2025 13:20:54 +0200</pubDate>
    </item>
    <item>
      <title>proof of work</title>
      <link>https://evilcookie.de/proof-of-work.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Proof of work</h1>

<p><a href="https://en.wikipedia.org/wiki/Proof_of_work">Proof of work</a> plays an interesting role within <a href="https://link.springer.com/referenceworkentry/10.1007/978-3-642-27739-9_1663-1">secure networking</a>, <a href="https://eprint.iacr.org/2010/649.pdf">DDoS protection</a> and an essential role creating blockchains aka mining coins<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>.</p>

<h2>Hash functions</h2>

<p>It is basically a concept of enforcing brute-force work that can&rsquo;t be skipped or worked around. This can be accomplished by
using a hash function which is by design not reversible. Hash functions compact an input with variable size into an output with fixed size.
Because of the reduction, there is no way of mapping an output back to an input.</p>

<p>A loose analogy can be an addition of arbitrary numbers. Just the sum won&rsquo;t tell you anything about the count of summands nor their value. There are
infinite possible additions that have this sum as a result. In reality it&rsquo;s more complex with substitution, shifting, modulo, padding and ominous s-boxes. Within my
cs studies, I implemented the obsolete <a href="https://github.com/RaphaelPour/md2">MD2</a> hash function, which is one of the more simple ones out there. Go check it out if you&rsquo;re curious!</p>

<h2>Practice</h2>

<p>Proof of works asks an opponent to do some work by asking something like <em>Give me an SHA1 hash starting with the string &lsquo;dead&rsquo;.</em>
As we have no other choice than guessing, we need to do the actual work:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">[9] pry(main)&gt; (0...).find{Digest::SHA1.hexdigest(_1.to_s).start_with?(&#39;dead&#39;)}
</span></span><span class="line"><span class="cl">=&gt; 42968
</span></span><span class="line"><span class="cl">[10] pry(main)&gt; (0...).find{Digest::SHA1.hexdigest(_1.to_s).start_with?(&#39;beef&#39;)}
</span></span><span class="line"><span class="cl">=&gt; 38838
</span></span><span class="line"><span class="cl">[11] pry(main)&gt; (0...).find{Digest::SHA1.hexdigest(_1.to_s).start_with?(&#39;deadbeef&#39;)}
</span></span><span class="line"><span class="cl">=&gt; 2943513
</span></span></code></pre>
<p><small style="color:rgba(0,0,0,0)">+hf</small></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Cryptocurrencies are bad, please don&rsquo;t use them. They&rsquo;re speculation and a huge waste of energy while <a href="https://www.youtube.com/watch?v=45D7n8tvMho">they don&rsquo;t solve any problem at all</a>.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Thu, 13 Mar 2025 05:26:40 +0100</pubDate>
    </item>
    <item>
      <title>FOSDEM 2025</title>
      <link>https://evilcookie.de/fosdem-2025.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>FOSDEM 2025</h1>

<p><img src="fosdem-2025_sticker.jpg"/></p>

<p>I attended the <a href="https://fosdem.org/2025/">FOSDEM 2025</a> in Brussels for the first time<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>.</p>

<p>Some data:</p>

<ul>
<li>from 1st to 2nd of February 2025</li>
<li>at the <a href="https://www.ulb.be/en">Université libre de Bruxelles</a> in Brussels</li>
<li>spotted creators of prominent software:

<ul>
<li><a href="https://daniel.haxx.se/blog/">Badger</a>: creator of <a href="https://curl.se/">cURL</a></li>
<li><a href="https://0pointer.net/blog/">PID 1</a>: creator of <a href="https://systemd.io/">systemd</a></li>
<li><a href="https://github.com/geraldcombs">Gerald Combs</a>: creator of <a href="https://www.wireshark.org/">wireshark</a></li>
</ul></li>
</ul>

<h3>Content</h3>

<ul>
<li><a href="#syd">Syd - Sandboxing for Linux</a></li>
<li><a href="#curl">Tightening every bolt</a></li>
<li><a href="#contributor">The selfish contributor revisited</a></li>
<li><a href="#systemd">14 years of systemd</a></li>
<li><a href="#prometheus3">Prometheus 3.0</a></li>
<li><a href="#auto-instrumentation">The performance impact of auto-instrumentation</a></li>
<li><a href="#leslie-lamport">Was Leslie Lamport Right?</a></li>
<li><a href="#wireshark">Wiresharchaeology - How it started and where we&rsquo;re headed</a></li>
<li><a href="#impressions">Impressions</a></li>
</ul>

<h2>Syd - Sandboxing for Linux<a id='syd'/></h2>

<p><a href="https://github.com/alip/">Ali Polatel</a> <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-4176-syd-an-introduction-to-secure-application-sandboxing-for-linux/">presented</a> the sandboxing framework <a href="https://docs.rs/syd/latest/syd/">syd</a>, giving insights about its mechanism and scopes. Originally named syd-box,</p>

<p>What makes this sandboxing tool stand out is the profile generation of an application, where syd records every resource access. It then creates a file containing a profile that would be needed to run the corresponding application.</p>

<p>Then the profile can be edited manually to restrict the behavior. The performance impact due to the sandboxing overhead is about 10-15%. The user can be unprivileged.</p>

<p>Some loose terms for further research: <a href="https://man7.org/linux/man-pages/man2/seccomp.2.html">seccomp</a>, <a href="https://www.man7.org/linux/man-pages/man2/ptrace.2.html">ptrace</a>, <a href="https://man.openbsd.org/pledge.2">pleage</a>, <a href="https://www.man7.org/linux/man-pages/man7/cgroups.7.html">cgroup</a>, <a href="https://man7.org/linux/man-pages/man7/landlock.7.html">landlock</a></p>

<h3>checkout pandora</h3>

<p>I&rsquo;ve checked out the profile generation but couldn&rsquo;t get syd to run with the generated profile for <code>echo &quot;Hello syd!&quot;</code>.</p>

<p>Here is the generated profile anyway:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">#
</span></span><span class="line"><span class="cl"># Syd profile generated by Pandora-0.12.1
</span></span><span class="line"><span class="cl"># PROG: echo
</span></span><span class="line"><span class="cl"># ARGS: [&#34;Hello syd!&#34;]
</span></span><span class="line"><span class="cl"># DATE: 20250203T130152Z
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">###
</span></span><span class="line"><span class="cl"># Sandbox Rules
</span></span><span class="line"><span class="cl">###
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">allow/exec,read+/usr/lib64/libc.so.6
</span></span><span class="line"><span class="cl">allow/exec,read+/usr/lib64/libdl.so.2
</span></span><span class="line"><span class="cl">allow/exec,read+/usr/lib64/libpthread.so.0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">allow/exec+/usr/bin/echo
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">allow/read+/etc/ld.so.cache
</span></span><span class="line"><span class="cl">allow/read,stat+/etc/ld.so.preload
</span></span><span class="line"><span class="cl">allow/read+/proc/self/status
</span></span><span class="line"><span class="cl">allow/read+/usr/lib/locale/***
</span></span><span class="line"><span class="cl">allow/read+/usr/lib64/gconv/***
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">###
</span></span><span class="line"><span class="cl"># Executable Verification
</span></span><span class="line"><span class="cl">###
</span></span><span class="line"><span class="cl">sandbox/force:on
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">force+/usr/bin/echo:238bfa90d90a7ec515b86fd173d61e27a4b647faa740f0960512107e03fb07b6443fa5be4482beeda34be755a6420029e1e305c91ca6e469a3af4dbd72aa8a7a
</span></span><span class="line"><span class="cl">force+/usr/lib64/libc.so.6:5cea972d42489450435f2efc186a4e8feb843e87243575aec48e054e219620e513d663bb6613393fbffa7da7cd3ecb645b014b72e70bc574289ad2e4bbd08fc1
</span></span><span class="line"><span class="cl">force+/usr/lib64/libdl.so.2:dd9ad3e5dee475491188902d009a1ca1f5e92812a51915b4535f88ea29628e2544cf05fb564584780c47d6e52c5eb4d8b888c2cfa7d14543cc0025a9b81a26b0
</span></span><span class="line"><span class="cl">force+/usr/lib64/libpthread.so.0:8dfae8d5058d8681ef3110f8325d8b3bc9d4f0f243f583c2d3857e660a2a9ea8b31afd9dc69af03fde3396bddb453e1c83d0142e8398ea26410563fb46e7b10b
</span></span></code></pre>
<h2>Tightening every bolt<a id='curl'/></h2>

<p>Daniel Stenberg (aka Badger) <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-4204-tightening-every-bolt/">talked</a> about keeping a c project like <a href="https://curl.se">curl</a> reliable and maintainable. Curl has 180k lines of C code and has about 20 billion installations.</p>

<p>I&rsquo;m fascinated about his commitment maintaining a project for such a long time and sticking with the language, resisting hypes such as rust-rewrites.</p>

<p>Some key concepts of keeping curl reliable:</p>

<ul>
<li>strict code</li>
<li>banned c functions like gets or sprintf</li>
<li>external audits</li>
<li>torture tests, ci and testing in general</li>
</ul>

<h2>The selfish contributor revisited<a id='contributor'/></h2>

<p>The <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-6540-the-selfish-contributor-revisited/">talk</a> by James Bottomley was about the motivation of contributors and the dynamics of open source communities.</p>

<ul>
<li>different people with different interests and views are key</li>
<li>politics: manipulation via incentives</li>
<li>open source communities grow without funding</li>
<li>switch roles and argument for the position of the opponent</li>
</ul>

<h2>14 years of systemd<a id='systemd'/></h2>

<p>Lennart Poettering is the developer behind the famous init system <a href="https://systemd.io/">systemd</a> which he created 14 years ago. His <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-6648-14-years-of-systemd/">Talk</a> reflects all those years.</p>

<p>Back in the days the most prominent systems <a href="https://wiki.archlinux.org/title/SysVinit">sysvinit</a> and <a href="https://en.wikipedia.org/wiki/Upstart_(software)">upstart</a> existed. They were more imperative and script oriented. There was the need of something more declarative where the system itself resolves the dependencies using a transactional system.</p>

<ul>
<li>690k lines of C code</li>
<li>babykit was the original project name inspired by <a href="https://en.wikipedia.org/wiki/Polkit">polkit</a></li>
<li>motivation for doing another init system was socket activation from Apple&rsquo;s launchd</li>
<li><a href="https://all-systems-go.io/">All system Go!</a> in Berlin is the systemd/service conference formerly known as systemd.conf</li>
<li>vision: replace <a href="https://en.wikipedia.org/wiki/D-Bus">dbus</a> with <a href="https://lwn.net/Articles/742675/">varlink</a></li>
</ul>

<h2>Prometheus 3.0<a id='prometheus3'/></h2>

<p>Prometheus is now 12 years old and while it belongs to <a href="https://www.cncf.io/">CNCF</a> for a while, it was originally created at soundcloud. <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-6571-prometheus-version-3/">This talk</a> held by <a href="https://fosdem.org/2025/schedule/speaker/jan_fajerski/">Jan Fajerski</a> from <a href="https://www.redhat.com/en">Red Hat</a> and <a href="https://fosdem.org/2025/schedule/speaker/bryan_boreham/">Bryan Boreham</a> from <a href="https://grafana.com/">Grafana Labs</a>.</p>

<p>Some new features with 3.0:</p>

<ul>
<li>new UI with reasoning about mismatching metrics</li>
<li>Remote Write 2.0 specification</li>
<li>UTF-8 support enabled by default</li>
</ul>

<p>On a side note, they ironically talked about major and patch releases and that you should always wait for the patch release after a major one. That sounds pretty reasonable while major versions might contain breaking changes and sometimes real user workload is needed to identify issues.</p>

<h2>The performance impact of auto-instrumentation<a id='auto-instrumentation'/></h2>

<p><a href="https://fosdem.org/2025/schedule/speaker/james_belchamber/">James Belchamber</a> <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-5502-the-performance-impact-of-auto-instrumentation/">talked</a> about the performance impact of open telemetries <a href="https://github.com/open-telemetry/opentelemetry-go-instrumentation/">auto instrumentation</a> in comparison with manual one. Auto instrumentation is about adding instrumentation to an application without doing the implementation work with defining spans.</p>

<ul>
<li>consistent while not reimplemented in every app</li>
<li>little bit more ram</li>
<li>application with significant load and does more than just request/response is mostly not impacted by auto instrumentation</li>
<li>apache httpd with the it works site is significantly slower, static small content is hugely impacted by instrumentation</li>
</ul>

<h2>Was Leslie Lamport Right?<a id='leslie-lamport'/></h2>

<p><a href="https://fosdem.org/2025/schedule/speaker/sarah_christoff/">Sarah Christoff</a> and <a href="https://fosdem.org/2025/schedule/speaker/nic_jackson/">Nic Jackson</a> from <a href="https://www.hashicorp.com/">HashiCorp</a> <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-4941-was-leslie-lamport-right-/">talked</a> about if Leslie Lamport and his work about distributed systems. He published a bunch of papers and the two revisit some of them and explain them.</p>

<p>It started with explaining the general <a href="https://en.wikipedia.org/wiki/Byzantine_fault">Byzantine fault</a> and the more specialized [two generals problem](<a href="https://en.wikipedia.org/wiki/Two_Generals'_Problem">https://en.wikipedia.org/wiki/Two_Generals&rsquo;_Problem</a>) which is about consensus between several systems/nodes. Lamport suggested <code>3m+1</code> generals to compensate <code>t+1</code> traitors. Traitors are intercepting and manipulating the consensus.</p>

<p>Lamport clocks are used to avoid synchronization problems between different clocks. Such clocks are logical and consists of a counter increased for every event such as sent and received event.</p>

<h2>Wiresharchaeology - How it started and where we&rsquo;re headed<a id='wireshark'/></h2>

<p>The create of <a href="https://www.wireshark.org/">wireshark</a> <a href="">Gerald Combs</a> held a <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-6726-wiresharchaeology-how-it-started-and-where-we-re-headed/">talk</a> about its history. Back in the days, sniffers to debug networks only existed within expensive hardware. Since Gerald couldn&rsquo;t convince his contrator back then to do this investment, he decided to build his own tool. This is how wireshark was born.</p>

<p>The original goal was to analyse packets in the network and evolved to &ldquo;Help as many people as possible to understand their networks and systems&rdquo;.</p>

<p>After switching companies for a few times he founded the non-profit wireshark foundation to ensure the financial situation.</p>

<p>Coming up next is <a href="stratoshark.org">StratoShark</a> for analyze applications on a syscall level which sounds like strace with an user interface.</p>

<h2>Impressions<a id='impressions'/></h2>

<p><img src="fosdem-2025_waffles.jpg"/></p>

<ul>
<li>lots of levels</li>
<li>visited eu parlament</li>
<li>belgian waffles were super delicious</li>
</ul>

<p><small style="color:rgba(0,0,0,0)">+rv=tch1b0</small></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">It was also the first time in Belgium for me.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 04 Feb 2025 20:00:00 +0100</pubDate>
    </item>
    <item>
      <title>38c3</title>
      <link>https://evilcookie.de/38c3.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>38c3 - illegal instructions</h1>

<p><img src="38c3_logo.png"/></p>

<p>I attended my first <a href="https://events.ccc.de/congress/2024/infos/index.html">CCC</a> (Chaos Computer Congress) in Hamburg. I came for the talks and stayed for all the rabbit holes I fell into.</p>

<p>Some data:</p>

<ul>
<li>location: <a href="https://www.cch.de/en">CCH Hamburg</a></li>
<li><a href="https://media.ccc.de/b/congress/2024">recorded lectures via media.ccc.de</a></li>
<li>motto: illegal instructions</li>
<li>date: 27.12.2024 - 30.12.2024</li>
<li>talk of the town with press embargo and international media echo: <a href="https://media.ccc.de/v/38c3-wir-wissen-wo-dein-auto-steht-volksdaten-von-volkswagen">Wir wissen wo dein Auto steht</a></li>
</ul>

<h4>Content</h4>

<ul>
<li><a href="#talks">Talks</a>

<ul>
<li><a href="#fnord">FNord Jahresrueckblick</a></li>
<li><a href="#io_uring">io_uring, eBPF, XDP and AF_XDP</a></li>
<li><a href="#rowhammer">Ten Years of Rowhammer: A Retrospect (and Path to the Future)</a></li>
<li><a href="#attack-mining">Attack Mining: How to use distributed sensors to identify and take down adversaries</a></li>
<li><a href="#recommendations">Further recommendations</a></li>
</ul></li>
<li><a href="#sidequests">Sidequests</a>

<ul>
<li><a href="#dect">DECT</a></li>
<li><a href="#soldering">Soldering</a>

<ul>
<li><a href="#led-animals">LED Animals</a></li>
<li><a href="#kippenautomat">Kippenautomat</a></li>
<li><a href="#ardutouch">ArduTouch Music Synthesizer</a></li>
</ul></li>
<li><a href="#keyboard-meetup">Keyboard meetup</a></li>
<li><a href="#neurodivergent-meetup">Neurodivergent meetup</a></li>
<li><a href="#workshop">TinyGS workshop</a></li>
</ul></li>
<li><a href="#impressions">Some impressions</a></li>
</ul>

<h2>Talks<a id='talks'/></h2>

<h3>FNord Jahresrueckblick<a id='fnord'/></h3>

<p>It was nice to see <a href="https://blog.fefe.de/">fefe</a> in rl with the famous <a href="https://media.ccc.de/v/38c3-fnord-nachrichtenrckblick-2024">FNord Jahresruecklick</a> about security related
news in the year 2024.</p>

<h3>io_uring, eBPF, XDP and AF_XDP <a id='io_uring'/></h3>

<p><a href="https://media.ccc.de/v/38c3-iouring-ebpf-xdp-and-afxdp">Talk</a> gave an overview over the <a href="https://unixism.net/loti/index.html">io_uring</a> concept such as <a href="https://en.wikipedia.org/wiki/Express_Data_Path">XDP</a> and its opportunity.</p>

<p>io_uring allows to give the kernel some userspace buffer for IO operations obsoleting all the read/write calls. XDP (short for eXpress Data Path) bypasses the whole linux network stack an enables custom packet handling, as seen in the <a href="https://en.wikipedia.org/wiki/Express_Data_Path#/media/File:Netfilter-packet-flow.svg">famous XDP diagram</a>.</p>

<h3>Ten Years of Rowhammer: A Retrospect (and Path to the Future)<a id='rowhammer'/></h3>

<p>The people around rowhammer summarized the attack itself such as further papers and scenarios that came up since its first release 10 years ago in <a href="https://media.ccc.de/v/38c3-ten-years-of-rowhammer-a-retrospect-and-path-to-the-future">this talk</a>.
They also stated, that all the studies together share a low amount of real systems where the attacks has been proven to work successfully. In order to gain more real world data and to underline that rowhammer is a real world threat, they asked for participation using their custom os.
The os contain the attacks itself such as some reverse engineering stuff to parameterize the attacks based on the given hardware.</p>

<p>Oh, and they also provided some live USB sticks as goddie containing the os image. Nice try!<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">1</a></sup></p>

<h3>Attack Mining: How to use distributed sensors to identify and take down adversaries <a id='attack-mining'/></h3>

<p>This was a <a href="https://media.ccc.de/v/38c3-attack-mining-how-to-use-distributed-sensors-to-identify-and-take-down-adversaries">journey</a> from analyzing bad login attempts in the <code>auth.log</code> over identifying a bot net finishing in contacting the ISP&rsquo;s of the compromised server. I like how the talk starts quite naive with some curiosity about the login attempts and goes deeper into the rabbit hole step by step.</p>

<h3>Further recommendations<a id='recommendations'/></h3>

<ul>
<li><a href="https://media.ccc.de/v/38c3-blmba-behind-the-scenes-of-a-2000s-style-ringtone-provider">Blamba - behind the scenes of a 2000s style ringtone provider</a></li>
<li><a href="https://media.ccc.de/v/38c3-hacking-life-how-to-decode-and-manipulate-biological-cells-with-ai">Hacking Life: How to decode and manipulate biological cells with AI</a></li>
<li><a href="https://media.ccc.de/v/38c3-hacker-s-guide-to-meshtastic-off-grid-encrypted-lora-meshnets-for-cheap">Hacker&rsquo;s Guide to Meshtastic: Off-Grid, Encrypted LoRa Meshnets for Cheap!</a></li>
<li><a href="https://media.ccc.de/v/38c3-knste-hacken">Knaeste hacken</a></li>
</ul>

<h2>Sidequests<a id='sidequests'/></h2>

<h3>DECT<a id='dect'/></h3>

<p>Sidequest of day one was to get my dect phone working. Well in the end my  Doro Comfort 1010 wasn&rsquo;t supported and my other FritzFon didn&rsquo;t boot&hellip;</p>

<p>Simcards to the rescue! I got one for my dual-sim mobile phone and registered my extension 25010.</p>

<p><img src="38c3_phonebook.png"/></p>

<h3>Soldering<a id='soldering'/></h3>

<p>There was a soldering area with fully equipped work places and a donation-based supply for some kits.</p>

<p><img src="38c3_soldering.jpg"/></p>

<h4>LED Animals<a id='led-animals'/></h4>

<p><img src="38c3_led_animals2.jpg"/>
<img src="38c3_led_animals1.png"/>
<img src="38c3_led_animals.gif"/></p>

<p>The axolothle was a good first soldering project to get back into the game. The cat was my very first smd project, and it went quite well \o/</p>

<h4>Kippenautomat<a id='kippenautomat'/></h4>

<p><img src="38c3_kippenautomat.png"/></p>

<p>One of my favorite things at the congress was the <a href="kippenautom.at">Kippenautomat</a> where one can get electronics for five bucks. Especially the &ldquo;random electronic circuit&rdquo; got my attention.</p>

<p>My first random circuit kippenschachtel was a spinner with blinking LED&rsquo;s on it</p>

<p><img src="38c3_kreisel.gif"/></p>

<h4>ArduTouch Music Synthesizer<a id='ardutouch'/></h4>

<p>At the assembly hall, I stumbled across several (actually 9) synthesizers looking the same but sounding different<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">2</a></sup>.  <a href="https://en.wikipedia.org/wiki/Mitch_Altman">Mitch</a> told me that he developed the whole synth himself in the last eight yrs. There are also not nine different circuits but only one that can be programmed in several ways enabled by the underlying <a href="https://www.microchip.com/en-us/product/ATmega32">ATmega32</a> chip.</p>

<p>It&rsquo;s called <a href="https://cornfieldelectronics.com/cfe/projects/ardutouch/ArduTouchAssemblyV12revC_r4.pdf">ArduTouch Music Synthesizer</a>.</p>

<p><img src="38c3_ardutouch.png"/></p>

<h3>Keyboard meetup<a id='keyboard-meetup'/></h3>

<p>It was fun peering with all those people which also fell into the rabbit hole and even created their own board.</p>

<p>The &ldquo;Tr9shpad&rdquo; got my attention, which is a 18-key keyboard with two rotary encoders and a display. It&rsquo;s key mapping allows T9-style tap-dancing and it &ldquo;should be helt like a gameboy&rdquo;. I also got one PCB to build my own one! \o/</p>

<p><img src="38c3_tr9shpad.png"/></p>

<h3>Neurodivergent meetup<a id='neurodivergent-meetup'/></h3>

<p>This was the very first appointment I attended to at the conference. The focus was on stimming. This was an eye opener for me, as I stim&rsquo; all the time but didn&rsquo;t know there is a topic that articulates this behavior pretty well. Or as <a href="https://en.wikipedia.org/wiki/Stimming">wikipedia</a> describes it:</p>

<blockquote>
<p>Stimming has been interpreted as a protective response to overstimulation, in which people calm themselves by blocking less predictable environmental stimuli, to which they have a heightened sensitivity.</p>
</blockquote>

<p>Another topic related to stimming was <a href="https://en.wikipedia.org/wiki/Autistic_masking">masking/camouflaging</a>: hiding neurodivergency by trying to mimic neurotypical behavior. I often notice this myself of trying to avoid stimming or have a guilty concense about doing it<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>.</p>

<p>There were also all kinds of fidget toys that were passed around, reminding me of my other blog article about <a href="https://evilcookie.de/thinking-tools-aka-fidget-toys.html">thinking toys</a>.</p>

<h3>TinyGS workshop<a id='workshop'/></h3>

<p>I attended the <a href="https://events.ccc.de/congress/2024/hub/en/event/build-your-own-satellite-ground-station/">Build Your Own Satellite Ground Station workshop</a> using a self-bent antenna, <a href="">Lilygo</a><a href="https://lilygo.cc/products/t3-tcxo">https://lilygo.cc/products/t3-tcxo</a> such as <a href="https://tinygs.com/">TinyGS</a>.</p>

<p>Some data:</p>

<ul>
<li><a href="https://www.tog.ie/wp-content/uploads/2024/06/Build-Your-Own-Satellite-Ground-Station-TinyGS-compressed.pdf">Instructions</a></li>
<li>Statelites we receive data from: <a href="https://en.wikipedia.org/wiki/CubeSat">CubeSat</a></li>
<li>Some <a href="https://earthobservatory.nasa.gov/features/OrbitsCatalog">NASA explaination</a> about orbits</li>
</ul>

<p><img src="38c3_antenna0.jpg"/>
<img src="38c3_antenna1.jpg"/>
<img src="38c3_tinygs.gif"/></p>

<p>My ground station is now <a href="https://tinygs.com/station/evilcookies_gs@14918118">collecting some cool data from <del>space</del> low earth orbit</a>.</p>

<h2>Some impressions<a id='impressions'/></h2>

<p><img src="38c3_impression1.png"/>
<img src="38c3_impression2.png"/></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:2">Don&rsquo;t just use USB sticks handed out by some untrusted thirds. To their defense, <a href="https://media.ccc.de/v/38c3-ten-years-of-rowhammer-a-retrospect-and-path-to-the-future#t=1934">that&rsquo;s what they also said in the end</a>.</li>

<li id="fn:1">The bass with the super saw is my favorite which turns out to be the default \o/</li>

<li id="fn:3">Well, no guilt from now on as I&rsquo;m more aware \o/</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 17 Jan 2025 12:01:01 +0100</pubDate>
    </item>
    <item>
      <title>Generic swapping in go</title>
      <link>https://evilcookie.de/generic-swapping-in-go.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Generic swapping in go</h1>

<p>When writing tests, overriding global values/defaults<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> can become pretty handy for mocking. But as always with global
resources, they need to be used carefully<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>. Otherwise other tests may behave strangely. Therefore a test should make sure those values are reset to its original value regardless of the test result.</p>

<p>Here you go: A generic swapper that gives you a resetter that can be easily called via defer (<a href="https://go.dev/play/p/-r6_5TNKHaz">playground</a>):</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nx">Swap</span><span class="p">[</span><span class="nx">T</span> <span class="nx">any</span><span class="p">]</span><span class="p">(</span><span class="nx">target</span> <span class="o">*</span><span class="nx">T</span><span class="p">,</span> <span class="nx">newValue</span> <span class="nx">T</span><span class="p">)</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">original</span> <span class="nx">T</span>
</span></span><span class="line"><span class="cl">  <span class="nx">original</span><span class="p">,</span> <span class="o">*</span><span class="nx">target</span> <span class="p">=</span> <span class="o">*</span><span class="nx">target</span><span class="p">,</span> <span class="nx">newValue</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="o">*</span><span class="nx">target</span> <span class="p">=</span> <span class="nx">original</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>You can even use it with defer directly:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">HTTPTest</span><span class="p">(</span><span class="nx">t</span> <span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">T</span><span class="p">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">defer</span> <span class="nf">Swap</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">DefaultClient</span><span class="p">,</span> <span class="nx">myClient</span><span class="p">)</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Don&rsquo;t forget the additional empty parenthesis at the end to call the returned function. Otherwise the swap takes only place on defer.</p>

<p><small style="color:rgba(0,0,0,0)">+hf</small></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Think of <a href="https://pkg.go.dev/net/http#DefaultClient">net/http&rsquo;s default client</a> that can handily be overridden for mocking.</li>

<li id="fn:2">Or not mutable at all. In the end, state is the developers greatest fear. Can you imagine a stateless world? Pretty boring, right?</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 10 Jan 2025 06:00:00 +0100</pubDate>
    </item>
    <item>
      <title>Local-only gitignore</title>
      <link>https://evilcookie.de/local-only-gitignore.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Local-only gitignore</h1>

<p><img src="local-only-gitignore_gitignore.png"/>
<small style="color:gray">Red passenger traffic light in Munich. Taken while doing some street photography with <a style="color:gray" href="auch.cool">flipez</a>.</small></p>

<p>tl;dr: Enable a local-only untracked gitignore file for all repos using the config option <code>core.excludeFiles</code>.</p>

<p>Gitignore is a great way of excluding unwanted files from a git repository. Usually you want to track it within the repo
and add all the coverage, binary or test files that get produced during the build process.</p>

<p>This is fine as long as you want to track all unwanted files in each git repo. Everyone uses vim, so ignoring swap files is fine, too.
But there are a bunch of individual tools and editors that place files in the repo which need to be added over and over again by each individual for each repo.</p>

<p>Git has support for a global gitignore file that gets applied in each repo without tracking it in each one: <code>config.excludeFiles</code></p>

<h2>Motivation</h2>

<p>Recently I started to use <code>rbenv</code> for managing my ruby installations. Setting a ruby version in the current repository
creates a file <code>.ruby-version</code>. I don&rsquo;t want to add this file to any existing ruby repo just because I&rsquo;m using it while other colleagues don&rsquo;t.</p>

<h2>Usage</h2>

<p>Create an individual gitignore file outside of any repo , e.g. in your home dir:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">.ruby-version
</span></span></code></pre>
<p>Then just add it to the local git config (usually <code>~/.gitconfig</code>):</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">&gt; git config --global core.excludeFiles=&lt;path to your gitignore&gt;
</span></span></code></pre>
<p><small style="color:rgba(0,0,0,0)">+hf</small></p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 16 Dec 2024 11:46:53 +0100</pubDate>
    </item>
    <item>
      <title>go yolo</title>
      <link>https://evilcookie.de/go-yolo.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>go yolo</h1>

<p><img src="go-yolo_yolo.png"/>
<small style="color:gray">Green passenger traffic light in Munich. Taken while doing some street photography with <a href="auch.cool">flipez</a>.</small></p>

<p>tl;dr Go generics can be used to drop the error of two-return-value functions to enable chaining functions quickly:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nx">Yolo</span><span class="p">[</span><span class="nx">T</span> <span class="nx">any</span><span class="p">]</span><span class="p">(</span><span class="nx">value</span> <span class="nx">T</span><span class="p">,</span> <span class="nx">_</span> <span class="kt">error</span><span class="p">)</span> <span class="nx">T</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">value</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// Atoi has signature func(s string) (int, error)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nf">Yolo</span><span class="p">(</span><span class="nx">strconv</span><span class="p">.</span><span class="nf">Atoi</span><span class="p">(</span><span class="s">&#34;21&#34;</span><span class="p">)</span><span class="p">)</span> <span class="o">+</span> <span class="nf">Yolo</span><span class="p">(</span><span class="nx">strconv</span><span class="p">.</span><span class="nf">Atoi</span><span class="p">(</span><span class="s">&#34;21&#34;</span><span class="p">)</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// 42
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre>
<h3>Content</h3>

<ul>
<li><a href="#aoc">AoC error handling</a></li>
<li><a href="#error-handling">Error handling</a></li>
<li><a href="#no-error-handling">No error handling</a></li>
<li><a href="#yolo">Yolo</a></li>
<li><a href="#synonyms">Synonyms</a></li>
</ul>

<h2>AoC error handling<a id="aoc"/></h2>

<p>It&rsquo;s <a href="https://adventofcode.com/">advent of code</a> time again! My utility lib <a href="https://github.com/RaphaelPour/stellar">stellar</a> is growing with generators.</p>

<p>One thing bugged me over the years: error handling. In this post I want to show you my <code>Yolo</code> function that consumes any error of a function with only one other value.</p>

<h2>Error handling<a id="error-handling"/></h2>

<p>Error handling is extremely important for writing reliable and maintainable code. Once I started over with C, checking <code>errno</code> as often as possible saved me a load of time debugging.</p>

<p>On the other hand, error handling is time consuming when assumptions can be made. Like converting the aoc input consisting only of numbers.</p>

<h2>No error handling<a id="no-error-handling"></h2>

<p>In Golang, errors get returned and need to be handled explicitly. They can be ignored via &ldquo;_&rdquo; in an assignment, but by default it can&rsquo;t be left on chaining functions like this:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">AnswerOfLife</span><span class="p">(</span><span class="nx">a</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nx">a</span> <span class="o">==</span> <span class="mi">42</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">42</span><span class="p">,</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>  
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="nx">errors</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="s">&#34;The answer to the ultimate question of life, the universe, and everything not found&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nf">AnswerOfLife</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="o">+</span> <span class="nf">AnswerOfLife</span><span class="p">(</span><span class="mi">1337</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>This doesn&rsquo;t work, as <code>AnswerOfLife</code> has multiple return values: <code>multiple-value AnswerOfLife(42) (value of type (int, error)) in single-value context</code>.</p>

<h2>Yolo<a id="yolo"></h2>

<p>You only life once is my answer to this problem:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nx">Yolo</span><span class="p">[</span><span class="nx">T</span> <span class="nx">any</span><span class="p">]</span><span class="p">(</span><span class="nx">value</span> <span class="nx">T</span><span class="p">,</span> <span class="nx">_</span> <span class="kt">error</span><span class="p">)</span> <span class="nx">T</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">value</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>It takes the result of a function with two return values and drops the error.</p>

<p>This doesn&rsquo;t come without a prize. Our code compiles but due to the missing error handling, the result may be confusing. Our program now compiles and outputs <code>41</code>.</p>

<p>This is really bad for debugging. Therefore I created some variants that handle the error differently, depending on the situation:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nx">YoloBoom</span><span class="p">[</span><span class="nx">T</span> <span class="nx">any</span><span class="p">]</span><span class="p">(</span><span class="nx">value</span> <span class="nx">T</span><span class="p">,</span> <span class="nx">err</span> <span class="kt">error</span><span class="p">)</span> <span class="nx">T</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nb">panic</span><span class="p">(</span><span class="nx">err</span><span class="p">.</span><span class="nf">Error</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">value</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nx">YoloDefault</span><span class="p">[</span><span class="nx">T</span> <span class="nx">any</span><span class="p">]</span><span class="p">(</span><span class="nx">value</span> <span class="nx">T</span><span class="p">,</span> <span class="nx">err</span> <span class="kt">error</span><span class="p">)</span> <span class="nx">T</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">err</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="nx">value</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="kd">var</span> <span class="nx">def</span> <span class="nx">T</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">def</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>The first panics on error right away for situations where errors are unlikely. The second returns the default value of the value&rsquo;s type. The later is useful when erroneous function calls should not be considered in an addition as <code>YoloDefault</code> would just return zero.</p>

<h2>Synonyms<a id="synonyms"></h2>

<ul>
<li><code>Must</code></li>
<li><code>Tja</code>: German word for &ldquo;oh well&rdquo;</li>
<li><code>OrPanic</code></li>
<li><code>Require</code></li>
</ul>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 03 Dec 2024 20:55:26 +0100</pubDate>
    </item>
    <item>
      <title>on-run commands on file event</title>
      <link>https://evilcookie.de/on-run-commands-on-file-event.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>on - run commands on file event</h1>

<p><img src="on-run-commands-on-file-event_ulriken.png"/>
<small style="color:gray">On top of the <a href="https://de.wikipedia.org/wiki/Ulriken">Ulriken</a> near <a href="https://en.wikipedia.org/wiki/Bergen">Bergen</a> in Norway from my last rl journey.</small></p>

<p>Inspired from <a href="https://linux.die.net/man/1/watch"><code>watch</code></a>, <a href="https://github.com/RaphaelPour/on"><code>on</code></a> runs commands repeatedly but on file events likewise to <a href="https://linux.die.net/man/1/inotifywait"><code>inotifywait</code></a>.</p>

<h4>Contents</h4>

<ul>
<li><a href="#getting-started">Getting started</a></li>
<li><a href="#origin-story">Origin story</a>

<ul>
<li><a href="#rustlings">Rustlings</a></li>
<li><a href="#watch-go-lint">Watch go lint</a></li>
<li><a href="#random-output">Random go lint output</a></li>
<li><a href="#file-events">File events</a></li>
</ul></li>
<li><a href="#implementation">Implementation</a>

<ul>
<li><a href="#fsnotify">Fsnotify</a></li>
<li><a href="#debounce">Debounce events</a></li>
</ul></li>
</ul>

<h2>Getting started<a id="getting-started"/></h2>

<p>usage:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">usage: on <span class="o">[</span>--create<span class="o">]</span> <span class="o">[</span>--write<span class="o">]</span> <span class="o">[</span>--rename<span class="o">]</span> <span class="o">[</span>--remove<span class="o">]</span> <span class="o">[</span>--chmod<span class="o">]</span> &lt;file&gt; &lt;cmd...&gt;
</span></span></code></pre>
<p>Listen to all events for a file and print date for each event:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ on ./main.go date
</span></span><span class="line"><span class="cl">Tue Nov  <span class="m">5</span> 12:27:53 PM CET <span class="m">2024</span>
</span></span><span class="line"><span class="cl">Tue Nov  <span class="m">5</span> 12:27:53 PM CET <span class="m">2024</span>
</span></span></code></pre>
<p>Run git diff for any write event:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ on --write ./main.go git diff
</span></span><span class="line"><span class="cl">diff --git a/main.go b/main.go
</span></span><span class="line"><span class="cl">index e400b66..baa2c16 <span class="m">100644</span>
</span></span><span class="line"><span class="cl">--- a/main.go
</span></span><span class="line"><span class="cl">+++ b/main.go
</span></span><span class="line"><span class="cl">@@ -17,8 +17,7 @@ var <span class="o">(</span>
</span></span><span class="line"><span class="cl">    <span class="nv">remove</span> <span class="o">=</span> flag.Bool<span class="o">(</span><span class="s2">&#34;remove&#34;</span>, false, <span class="s2">&#34;React on remove&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">    <span class="nv">chmod</span>  <span class="o">=</span> flag.Bool<span class="o">(</span><span class="s2">&#34;chmod&#34;</span>, false, <span class="s2">&#34;React on chmod&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-   <span class="nv">verbose</span> <span class="o">=</span> flag.Bool<span class="o">(</span><span class="s2">&#34;verbose&#34;</span>, false, <span class="s2">&#34;Print debug information&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">-
</span></span><span class="line"><span class="cl">+   <span class="nv">verbose</span>     <span class="o">=</span> flag.Bool<span class="o">(</span><span class="s2">&#34;verbose&#34;</span>, false, <span class="s2">&#34;Print debug information&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">    <span class="nv">listenToAll</span> <span class="o">=</span> <span class="nb">false</span>
</span></span><span class="line"><span class="cl"> <span class="o">)</span>
</span></span></code></pre>
<p>Debug output with all events:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ on --verbose ./main.go <span class="nb">true</span>
</span></span><span class="line"><span class="cl">ops: <span class="o">[</span><span class="o">]</span>fsnotify.Op<span class="o">{</span><span class="o">}</span>
</span></span><span class="line"><span class="cl">received REMOVE        <span class="s2">&#34;./main.go&#34;</span>
</span></span><span class="line"><span class="cl">received CREATE        <span class="s2">&#34;./main.go&#34;</span>
</span></span><span class="line"><span class="cl">received WRITE         <span class="s2">&#34;./main.go&#34;</span>
</span></span><span class="line"><span class="cl">received CHMOD         <span class="s2">&#34;./main.go&#34;</span>
</span></span><span class="line"><span class="cl">received RENAME        <span class="s2">&#34;./main.go&#34;</span>
</span></span><span class="line"><span class="cl">received CREATE        <span class="s2">&#34;./main.go&#34;</span>
</span></span><span class="line"><span class="cl">received WRITE         <span class="s2">&#34;./main.go&#34;</span>
</span></span><span class="line"><span class="cl">received WRITE         <span class="s2">&#34;./main.go&#34;</span>
</span></span><span class="line"><span class="cl">received CHMOD         <span class="s2">&#34;./main.go&#34;</span>
</span></span></code></pre>
<h2>Origin story<a id="origin-story"/></h2>

<h3>Rustlings<a id="rustlings"/></h3>

<p><a href="https://github.com/rust-lang/rustlings">Rustling</a> is a series of exercise the <a href="https://www.rust-lang.org/">rust programming language</a>, <a href="https://evilcookie.de/finish-rustlings.html">I completed a while ago</a>. Their approach to run the test suite and give immediate feedback was to just run the suite periodically, shortening the feedback loop and giving low-latency feedback. I underestimated the productivity of short feedback loops like this.</p>

<h3>Watch go lint<a id="watch-go-lint"/></h3>

<p>I adapted the watch pattern for fixing go linter issues by running <code>watch golangci-lint run</code>.</p>

<h3>Random go lint output<a id="random-output"/></h3>

<p>While rustlings provides ordered output, golangci-lint&rsquo;s output can be randomly sorted. I guess all the linter run in parallel and thus no output order is guaranteed.</p>

<h3>File events<a id="file-events"/></h3>

<p>Rather than periodically run the linter, I wanted to run it only when the file had changed. Luckily <a href="https://pkg.go.dev/github.com/fsnotify/fsnotify">fsnotify</a> provides a watcher to programatically react on file events like create, write, rename and even chmod<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>.</p>

<p>With this approach I can get a fresh linter output by saving my code file.</p>

<h2>Implementation<a id='implementation'/></h2>

<h3>Fsnotify<a id='fsnotify'/></h3>

<p>Using <a href="https://pkg.go.dev/github.com/fsnotify/fsnotify">fsnotify</a>, the following examples show the use of the file event watcher. It typically watches on directories rather than single files, like <a href="https://github.com/RaphaelPour/on"><code>on</code></a> does it with some additional filtering for convenience.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;os&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="s">&#34;github.com/fsnotify/fsnotify&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// first argument is the directory,
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// the watcher give us events for
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">2</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;usage: watch &lt;dir&gt;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">defer</span> <span class="nx">watcher</span><span class="p">.</span><span class="nf">Close</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">watcher</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">fsnotify</span><span class="p">.</span><span class="nf">NewWatcher</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// register the watcher
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">watcher</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">)</span><span class="p">;</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">defer</span> <span class="nx">watcher</span><span class="p">.</span><span class="nf">Remove</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// the watcher provides several channels to listen to
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">select</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// whenver a file event happened,
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// the watcher sends it to the Events channel
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">case</span> <span class="nx">event</span><span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="nx">watcher</span><span class="p">.</span><span class="nx">Events</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">!</span><span class="nx">ok</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// on error the watcher sends it to the Errors channel
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">case</span> <span class="nx">err</span><span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="nx">watcher</span><span class="p">.</span><span class="nx">Errors</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">!</span><span class="nx">ok</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;error:&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Which outputs something like the following. The watch command is sent to background in order to print events simultaneously within one terminal.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ ./watch /tmp <span class="p">&amp;</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>1<span class="o">]</span> <span class="m">1713</span>
</span></span><span class="line"><span class="cl">$ touch /tmp/test
</span></span><span class="line"><span class="cl">CREATE        <span class="s2">&#34;/tmp/test&#34;</span>
</span></span><span class="line"><span class="cl">CHMOD         <span class="s2">&#34;/tmp/test&#34;</span>
</span></span><span class="line"><span class="cl">$ <span class="nb">echo</span> <span class="m">123</span> &gt; /tmp/test
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;/tmp/test&#34;</span>
</span></span><span class="line"><span class="cl">$ rm /tmp/test
</span></span><span class="line"><span class="cl">REMOVE        <span class="s2">&#34;/tmp/test&#34;</span>
</span></span><span class="line"><span class="cl">$ touch /tmp/test
</span></span><span class="line"><span class="cl">CREATE        <span class="s2">&#34;/tmp/test&#34;</span>
</span></span><span class="line"><span class="cl">CHMOD         <span class="s2">&#34;/tmp/test&#34;</span>
</span></span><span class="line"><span class="cl">$ mv /tmp/test /tmp/test2
</span></span><span class="line"><span class="cl">RENAME        <span class="s2">&#34;/tmp/test&#34;</span>
</span></span><span class="line"><span class="cl">CREATE        <span class="s2">&#34;/tmp/test2&#34;</span> ← <span class="s2">&#34;/tmp/test&#34;</span>
</span></span><span class="line"><span class="cl">$ <span class="nb">fg</span>
</span></span><span class="line"><span class="cl">./watch .
</span></span><span class="line"><span class="cl">^C
</span></span></code></pre>
<h3>Debounce events<a id='debounce'/></h3>

<p>When saving a file, there is not necessarily only one event. The count grows with the file size while writing the content to disk gets fragmented. In the following snippet 100kib trigger a bunch of write events:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ ./watch . <span class="p">&amp;</span>
</span></span><span class="line"><span class="cl">$ dd <span class="k">if</span><span class="o">=</span>/dev/zero <span class="nv">of</span><span class="o">=</span><span class="nb">test</span> <span class="nv">bs</span><span class="o">=</span>1k <span class="nv">count</span><span class="o">=</span><span class="m">100</span> <span class="nv">status</span><span class="o">=</span>progress
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">WRITE         <span class="s2">&#34;./test&#34;</span>
</span></span><span class="line"><span class="cl">100+0 records in
</span></span><span class="line"><span class="cl">100+0 records out
</span></span><span class="line"><span class="cl"><span class="m">102400</span> bytes <span class="o">(</span><span class="m">102</span> kB, <span class="m">100</span> KiB<span class="o">)</span> copied, 0.000620291 s, <span class="m">165</span> MB/s
</span></span></code></pre>
<p>I want my linter to run only once per file save. Those events need to be squashed in a way that each save triggers its own command run.</p>

<p>We can make use of the debounce pattern, as described in the book <a href="https://www.oreilly.com/library/view/cloud-native-go/9781492076322/ch04.html">Cloud Native Go</a>. Frequent events get limit within a specified time frame into a single one as shown in the following diagram.</p>

<p><img src="on-run-commands-on-file-event_diagram.jpg"/></p>

<p>This concept is implemented in the event loop of <a href="https://github.com/RaphaelPour/on/blob/main/main.go">on</a> as shown here:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="c1">// create new thread-safe map
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">debounceMap</span> <span class="p">=</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">Map</span><span class="p">{</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">select</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">case</span> <span class="nx">event</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="nx">watcher</span><span class="p">.</span><span class="nx">Events</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// check if event already occured lately and was stored to the map
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// use the file name (event.name) as key
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">if</span> <span class="nx">t</span><span class="p">,</span> <span class="nx">found</span> <span class="o">:=</span> <span class="nx">debounceMap</span><span class="p">.</span><span class="nf">Load</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">Name</span><span class="p">)</span><span class="p">;</span> <span class="nx">found</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// if there already was an event lately, reset its timer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="nx">timer</span><span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="nx">t</span><span class="p">.</span><span class="p">(</span><span class="o">*</span><span class="nx">time</span><span class="p">.</span><span class="nx">Timer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="nx">timer</span><span class="p">.</span><span class="nf">Reset</span><span class="p">(</span><span class="o">*</span><span class="nx">debounceTimeout</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">continue</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// If the event occured the first time within the current timeframe, just
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// add it with a new timer as value to the map.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// The provided function gets called when the timer ran out.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">debounceMap</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">Name</span><span class="p">,</span> <span class="nx">time</span><span class="p">.</span><span class="nf">AfterFunc</span><span class="p">(</span><span class="o">*</span><span class="nx">debounceTimeout</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// remove the event again to end this debounce time frame
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="c1">// defer ensures that the command finished before the next timeframe starts 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="k">defer</span> <span class="nx">debounceMap</span><span class="p">.</span><span class="nf">Delete</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">Name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="c1">// just run it
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="nf">run</span><span class="p">(</span><span class="nx">command</span><span class="p">,</span> <span class="nx">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">case</span> <span class="nx">err</span><span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="nx">watcher</span><span class="p">.</span><span class="nx">Errors</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="o">...</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Based on <a href="https://linux.die.net/man/7/inotify">inotify</a></li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 06 Nov 2024 21:04:39 +0100</pubDate>
    </item>
    <item>
      <title>ferris sweep split keyboard build</title>
      <link>https://evilcookie.de/ferris-sweep-split-keyboard-build.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Ferris sweep split keyboard build</h1>

<p>I built a <a href="https://github.com/davidphilipbarr/Sweep">Ferris Sweep</a> split keyboard originated from the <a href="https://evilcookie.de/datenspuren-24.html#souvenirs">Datenspuren 24 souvenirs</a>. Having a bit soldering experience and hacking curiosity, this was/is a great rabbit hole to explore.</p>

<p><img src="ferris-sweep-split-keyboard-build_impression2.jpg"/></p>

<h4>Contents</h4>

<ul>
<li><a href="#starting-point">Starting point</a></li>
<li><a href="#preparation">Preparation</a>

<ul>
<li><a href="#components">Components</a></li>
<li><a href="#tools">Tools</a></li>
</ul></li>
<li><a href="#assembly">Assembly</a>

<ul>
<li><a href="#close-jumper">Close jumper pads on the opposite side</a></li>
<li><a href="#pin-header">Orthogonal pin header</a></li>
<li><a href="#pinecil">Pinecil</a></li>
<li><a href="#hazard">TRRS shorting hazard</a></li>
</ul></li>
<li><a href="#flashing">Flashing</a>

<ul>
<li><a href="#update">Chicken egg upate</a></li>
</ul></li>
<li><a href="#qmk">QMK</a>

<ul>
<li><a href="#own-keymap">Own keymap</a></li>
<li><a href="#home-row-mods">Home row mods</a></li>
<li><a href="#qwerty">QWERTY</a></li>
</ul></li>
<li><a href="#impressions">Impressions</a></li>
<li><a href="#summary">Summary</a></li>
</ul>

<h2>Starting point<a id='starting-point'/></h2>

<p><img src="ferris-sweep-split-keyboard-build_pcb.jpg"/></p>

<p>There are several Ferris Sweep variants out there. As I randomly chose this PCB at the keyboard-meetup of the last Datenspuren event, I first need to identify the variant. Due to the holes for <a href="https://splitkb.com/collections/keyboard-parts/products/kailh-hotswap-sockets">MX Hotswap sockets</a><sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> it looks like the <a href="https://github.com/davidphilipbarr/Sweep/tree/main/Sweep%20Bling%20MX">Bling MX</a> one.</p>

<p>My soldering skills are rather mediocre and I have some problems with soldering <a href="https://en.wikipedia.org/wiki/Surface-mount_technology">SMD</a>-sized components. This board luckily has mostly big pads or at least <a href="https://en.wikipedia.org/wiki/Dual_in-line_package">DIP</a> elements. Only the optional reset switch is SMD-sized.</p>

<h2>Preparation<a id='preparation'/></h2>

<p>Time to gather all needed components and tools.</p>

<h3>Components<a id='components'/></h3>

<p>Based on the <a href="https://github.com/davidphilipbarr/Sweep/tree/main/Sweep%20Bling%20MX/gerbers">Bling MX BOM</a>, the following components are needed:</p>

<ul>
<li>2x pro-micro-compatible microcontroller, bought recommended<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> <a href="https://keeb.supply/products/0xcb-helios">0xCB Helios</a></li>
<li>2x <a href="https://keycapsss.com/keyboard-parts/parts/142/pin-header-2x12-pins-1x-5-pins?c=11">pin header</a></li>
<li>34x <a href="https://www.amazon.de/Akko-Switch-V3-Pro-Cream-Blue/dp/B0CJY1GBYP">MX switches</a></li>
<li>34x <a href="https://splitkb.com/collections/keyboard-parts/products/kailh-hotswap-sockets">Kalih hotswap sockets</a></li>
<li>34x <a href="https://www.amazon.de/dp/B0BXXHKJ4X">key caps</a></li>
<li>2x <a href="https://keeb.supply/products/trrs-jack">TRRS jacks</a></li>
<li>1x <a href="https://splitkb.com/products/braided-trrs-cable">TRRS cable</a></li>
<li>1x USB-C cable</li>
</ul>

<p>Some optional reset switches would be useful for later flashing the microcontroller, but this can also be achieved by shorting two pins with a screwdriver.</p>

<p>As the switch- and bottom-plate is missing, I looked out and found a 3d model for printing the case myself:</p>

<ul>
<li><a href="https://www.printables.com/model/337694-sweep-bling-mx-sleeve-hard-case">Case model</a></li>
<li>6x M2 screws</li>
<li>6x M2 spacer</li>
<li>some rubber feet</li>
</ul>

<h3>Tools<a id='tools'/></h3>

<p>Soldering:</p>

<ul>
<li>soldering iron, bought recommended<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> <a href="https://pine64.com/product/pinecil-smart-mini-portable-soldering-iron/">Pinecil v2</a><sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup></li>
<li>solder tin<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup></li>
<li>optional: <a href="https://pine64.com/product/pinecil-portable-mini-stand/">sponge + stand</a>, handy for laying down the hot soldering iron</li>
<li>optional: <a href="https://www.adafruit.com/product/3536">silicon mat</a>, makes every table to a soldering work bench without fear of burning the surface</li>
</ul>

<p>Some other tools for assembly:</p>

<ul>
<li>screw driver</li>
<li>side cutter, for shorting the pin header legs after soldering</li>
</ul>

<h2>Assembly<a id='assembly'/></h2>

<p><a href="https://www.youtube.com/watch?v=53eY8GVntAU">There</a> <a href="https://www.youtube.com/watch?v=fBPu7AyDtkM">are</a> <a href="https://new.boardsource.xyz/docs/build_guides-sweep">several</a> <a href="https://andy.teknostatik.co.uk/blog/2023/10/03/ferris-sweep-build-guide/">tutorials</a> out there, so I only describe things I stumbled on.</p>

<h3>Close jumper pads on the opposite side<a id='opposite-side'/></h3>

<p><img src="ferris-sweep-split-keyboard-build_oppositeside.png"/></p>

<p>This was new to me and ambiguous:</p>

<ul>
<li>close pads on both PCB&rsquo;s on the opposite side of the microcontroller, or</li>
<li>close pads only on PCB opposite to the main one, while the circuitry might work different between left and right side</li>
</ul>

<p>The first alternative sounded more reasonable, as both sides should be built up equally.</p>

<h3>Orthogonal pin header<a id='pin-header'/></h3>

<p>In order to place the microcontroller properly onto the pin header, those headers need to be orthogonal to the PCB. I used a breadboard to align them properly, but it was rather fiddly.</p>

<h3>Pinecil<a id='pinecil'/></h3>

<p>Soldering iron with ARM chip, why?</p>

<p>It turns out the iron is pretty smart and provides some comfort, even with factory settings. The tip was hot in seconds, cooled down to 150°C when layed down and heated up again when picked up.</p>

<p>Despite the iron itself, the PCB was straight forward to solder. I really enjoyed soldering the hotswap sockets, due to the big pads.</p>

<p><img src="ferris-sweep-split-keyboard-build_hotswap.png"/></p>

<h3>TRRS shorting hazard<a id='hazard'/></h3>

<p>Neither connect nor disconnect the TRRS cable between the two sides while the USB-C cable is plugged in!</p>

<p>The TRRS cable drives the secondary side over the power supply from the primary one. Plugging in or out the cable can harm the components as it can short the power supply.</p>

<h2>Flashing<sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup><a id='flashing'/></h2>

<p><a href="https://qmk.fm/">QMK</a> is the firmware for such extraordinary <a href="https://en.wikipedia.org/wiki/Human_interface_device">human interface devices</a>. The <a href="https://docs.qmk.fm/newbs_getting_started">setup</a> is straight forward until the installation of the proper crosscompilation toolchain for the arm-based raspberry pi chip <a href="https://en.wikipedia.org/wiki/RP2040">RP2040</a> of the <a href="https://keeb.supply/products/0xcb-helios">0xCB Helios</a> on Fedora. I ended up installing the following packages:</p>

<ul>
<li><code>arm-none-eabi-binutils-cs.x86_64</code></li>
<li><code>arm-none-eabi-gcc-cs.x86_64</code></li>
<li><code>avr-libc.noarch</code></li>
<li><code>gcc-arm-linux-gnu.x86_64</code></li>
<li><code>binutils-arm-linux-gnu.x86_64</code></li>
<li><code>arm-none-eabi-gcc-cs-c++.x86_64</code></li>
<li><code>arm-none-eabi-newlib.noarch</code></li>
</ul>

<p>Build the default keymap: <code>qmk compile -kb ferris/sweep -km default -e CONVERT_TO=helios</code></p>

<p>Next step is to flash the microcontroller with our new firmware. Because my SMD-sized reset switches went missing, I used a screwdriver to short the <code>GND</code> with the <code>RST</code> pin in order to get the controller into flashing mode.</p>

<p>Then the controller get recognized as storage device. After copying our firmware onto the mounted device, it resets itself automatically ready to use the new mapping.</p>

<h3>Chicken egg upate<a id='update'/></h3>

<p>The keyboard needs to be booted and mounted in flash mode to copy the new firmware onto it. While in flash mode the keyboard is not usable.</p>

<p>Predicing the storage device name, this can be automated like this:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">sleep <span class="m">10</span> <span class="o">&amp;&amp;</span> sudo mount /dev/sda1 /mnt <span class="o">&amp;&amp;</span> sudo cp personal/qmk/ferris_sweep_beginning_helios.uf2 /mnt/ <span class="o">&amp;&amp;</span> sudo umount /mnt
</span></span></code></pre>
<h2>QMK<a id='qmk'/></h2>

<p>The <a href="https://docs.qmk.fm/">Quantum Mechanical Keyboard Firmware</a> (short QMK) is an Open-Source and highly customizable toolchain to build custom keyboard firmware. Some notable features that got my attention:</p>

<ul>
<li><a href="https://docs.qmk.fm/newbs_external_userspace">custom keymap</a> in <a href="github.com/RaphaelPour/qmk">its own repo</a>, build via <code>qmk compile -kb ferris/sweep -km beginning -e CONVERT_TO=helios</code></li>
<li><a href="https://docs.qmk.fm/features/combo">combos</a>: press multiple keys at once for a new key<sup class="footnote-ref" id="fnref:5"><a href="#fn:5">5</a></sup></li>
<li><a href="https://docs.qmk.fm/feature_layers">layer</a>: each key has multiple actions depending on the current layer, key modifiers are used to toggle a layer, e.g. <code>LT(layer, key)</code> toggle <code>layer</code> on hold and send key as usual on tap</li>
<li><a href="https://docs.qmk.fm/one_shot_keys">one-shot keys</a>: tap key once, it stays active until next key press</li>
<li><a href="https://docs.qmk.fm/features/send_string">send string</a>: send whole string like <code>return</code> on a programming layer</li>
<li><a href="https://docs.qmk.fm/features/rawhid">raw hid</a>: communicate out-of-bound with host system via <a href="https://docs.kernel.org/hid/hidraw.html">raw hid interface</a></li>
<li>inherited keys: layers can inherit keys from upper layer when not needed</li>
</ul>

<h3>Own keymap<a id='own-keymap'/></h3>

<p>QMK provides a <a href="https://config.qmk.fm">visual configurator</a> to build up new and modify existing keymaps. Starting with the <a href="https://github.com/qmk/qmk_firmware/tree/master/keyboards/ferris/keymaps/default">default map</a> for the ferris sweep, I now want to add my first own layer and it should provide everything number-related. I came up with this:</p>

<p><img src="ferris-sweep-split-keyboard-build_numberlayer.png"/></p>

<ul>
<li>top row numbers like on a common qwerty keyboard</li>
<li>cursed num-block on the left side that integrates the top number row nicely, this way often used numbers in the programming context like 0,1,2 are on the home row<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></li>
<li>basic arithmetic operator and punctuation</li>
</ul>

<h3>Home row mods<a id='home-row-mods'/></h3>

<p>The home row is the default finger position on the middle row, aligned towards the outer edge of each side.</p>

<p><img src="ferris-sweep-split-keyboard-build_homerow.jpg"/></p>

<p>Mods are the &ldquo;control keys&rdquo; to access other layers and in general modify the context of other keys. Pressing them accidentally, can disturb the writing flow. It&rsquo;s not only about pressing the wrong keys but also pressing them too short or long while keys with mods have different actions assigned.</p>

<p>Usually it is not recommended to add mods on the home row, to avoid false-positives, but with only 34-keys, its hard to avoid<sup class="footnote-ref" id="fnref:6"><a href="#fn:6">6</a></sup> .</p>

<h3>QWERTY<a id='qwerty'/></h3>

<p>As a german I&rsquo;m used to the QWERTZ keyboard layout. What I didn&rsquo;t know is that every keyboard is doing QWERTY and the os is mapping it to the configured one.</p>

<p>Switching to QWERTY makes configuring the ferris via QMK much easier as the mapping stays consistent and doesn&rsquo;t get remapped.</p>

<h2>Impressions<a id='impressions'/></h2>

<p><img src="ferris-sweep-split-keyboard-build_impression1.jpg"/>
<small>Me soldering together all the pieces.</small></p>

<p><img src="ferris-sweep-split-keyboard-build_impression2.jpg"/>
<small>The final keyboard with some sticker to help learning the layout. Pretzel-key is escape ftw.!</small></p>

<p><img src="ferris-sweep-split-keyboard-build_impression3.jpg"/>
<small>I really like the color combination of mictrocontroller and audio jack.</small></p>

<p><img src="ferris-sweep-split-keyboard-build_impression4.jpg"/>
<small>Under the switch</small></p>

<p><img src="ferris-sweep-split-keyboard-build_monkeytype.png"/>
<small>Monkeytype result after four days</small></p>

<h2>Summary<a id='summary'/></h2>

<p>The assembly was easier and more fun than I expected. The keyboard booted up right away and I had more progress learning the new key mapping than I imagined. <sup>10</sup>&frasl;<sub>10</sub> rabbit hole exploration!</p>

<p>It&rsquo;s still open if I use it as my main keyboard, as it&rsquo;ll cost a bunch of time to gain enough muscle memory to work up to the regular speed again.</p>

<p>I&rsquo;m already planing on improving the keycaps to minimize travel distance.</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Thanks to my split-keyboard guru/colleague for sharing knowledge, experience and recommendations!</li>

<li id="fn:2">The last soldering iron got heated to death and its tip got loose. Attention: The pinecil needs and USB-C power supply with enough watts. A notebook USB-C power supply did the job well for me.</li>

<li id="fn:3">Don&rsquo;t know which is the right tin for the job. I like those <a href="https://www.amazon.de/bleifreier-Kolophoniumkern-Zinndraht-elektrische-Heimwerker/dp/B07TDGZ45">tin pens</a>, to minimize skin contact.</li>

<li id="fn:4">Everything from here is written with the ferris sweep \o/</li>

<li id="fn:5">There are <a href="https://kbd.news/CLP-How-I-found-my-keycaps-2224.html">special keycaps</a> out there making combos more easily accessible by reducing the travel distance.</li>

<li id="fn:6">See <a href="https://precondition.github.io/home-row-mods">Home row mods</a></li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 22 Oct 2024 20:09:42 +0200</pubDate>
    </item>
    <item>
      <title>Last mile is always the hardest</title>
      <link>https://evilcookie.de/last-mile-is-always-the-hardest.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Last mile is always the hardest</h1>

<p><img src="last-mile-is-always-the-hardest_lastmile1.jpg"/>
<img src="last-mile-is-always-the-hardest_lastmile2.jpg"/>
<img src="last-mile-is-always-the-hardest_lastmile3.jpg"/></p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 30 Sep 2024 12:26:33 +0200</pubDate>
    </item>
    <item>
      <title>Datenspuren 24</title>
      <link>https://evilcookie.de/datenspuren-24.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Datenspuren 24</h1>

<p><img src="datenspuren-24_impression.jpg"/></p>

<p>I&rsquo;ve attended the <a href="https://datenspuren.de/2024/">Datenspuren 24</a> hosted by <a href="https://c3d2.de/">C3D2</a> in Dresden.</p>

<p>Some data:</p>

<ul>
<li>location: <a href="https://zentralwerk.de/">Dresden-Pieschen Zentralwerk</a></li>
<li>lot of talks, workshops and get together</li>
<li>since 2004</li>
<li>focus: technology within society</li>
<li>own payment system <a href="https://taler.net/de/">GNUTaler</a> with the digital currency <a href="https://datenspuren.de/2024/taler/index.html">Spurlos</a></li>
</ul>

<h3>Contents</h3>

<ul>
<li><a href="#sculptos-talk">SculptOS - a novel operating system, truly trustworthy computing</a>

<ul>
<li><a href="#microkernel">Microkernel mechanism</a></li>
<li><a href="#sculptos">SculptOS</a></li>
<li><a href="#edit-tryout">Update (26.09.2024) - Tryout</a></li>
</ul></li>
<li><a href="#sequoiapgp">SequoiaPGP - Implementation of PGP</a></li>
<li><a href="#travel-report">Travel report from the media jungle</a></li>
<li><a href="#lock-picking">Lock picking village - workshop</a></li>
<li><a href="#hex-hello-world">Linux hello world with hex editor</a>

<ul>
<li><a href="#hexylon">Hexylon</a></li>
</ul></li>
<li><a href="#speedhacking">Speedhacking</a></li>
<li><a href="#the-event">The event</a></li>
<li><a href="#souvenirs">Souvenirs and future rabbit holes</a></li>
<li><a href="#dd-impressions">DD Impressions</a></li>
</ul>

<h2>SculptOS - a novel operating system, truly trustworthy computing<a id='sculptos-talk'/></h2>

<p>If the wifi driver of a monolithic kernel (like Linux) crashes, the kernel crashes entirely. Compromizing one part of the kernel also enables access to all the other parts (<a href="https://nvd.nist.gov/vuln/detail/CVE-2024-1086">CVE-2024-1086</a>,<a href="https://nvd.nist.gov/vuln/detail/CVE-2024-36971">CVE-2024-36971</a>).  Microkernel prevent
this issue by separating all critical parts of a kernel from each other. <a href="https://genodians.org/atopia/index">Benjamin Lamowski</a> from <a href="https://www.genode-labs.com/">GenodeLabs</a> started <a href="https://talks.datenspuren.de/ds24/talk/XBNY7R/">the talk</a> (<a href="https://media.ccc.de/v/ds24-419-sculpt-os-a-novel-operating-system-for-truly-trustworthy-computing">video</a>) with this premise to show the advantages of the microkernel-based operating system <a href="https://genode.org/download/sculpt">SculptOS</a>.</p>

<h3>Microkernel mechanisms<a id='microkernel'/></h3>

<p>In order to achieve this separation, some mechanism comes into play:</p>

<ul>
<li>protect domains, two domains can only communicate if given permission</li>
<li>context switching</li>
<li><a href="https://en.wikipedia.org/wiki/Inter-process_communication">IPC</a> for connect domains</li>
<li>resource arbitration, control hardware access</li>
<li>principle of least authority</li>
<li>one component can&rsquo;t oversee the global system =&gt; like <code>chroot</code> for each domain</li>
<li>no overcommitment to achieve dependability</li>
</ul>

<h3>SculptOS<a id='sculptos'/></h3>

<p><img src="datenspuren-24_sculptoscomponents.png"/></p>

<p>The os provides components to isolate and connect domains.</p>

<p>Components can be connected on-the-fly within the config file or the UI.</p>

<p>The os reuses linux drivers to overcome reinventing the wheel. It keeps the scheduler and memory management within the kernel to avoid lots of context switching.</p>

<h3>Update (26.09.2024) - Tryout<a id='edit-tryout'/></h3>

<p>I&rsquo;ve downloaded the 30 megs image from <a href="https://genode.org/download/sculpt">their website</a> and pasted the qemu commandline right underneath adding <code>-accel kvm</code>, it worked out of the box \o/
The whole system along with its drivers can be configured with xml files life. Literally changing a value in the file will affect the system instantly. The immediate response makes it fun to play around and try things out.</p>

<p><img src="datenspuren-24_sculptostry.png"/></p>

<h2>SequoiaPGP - Implementation of PGP<a id='sequoiapgp'/></h2>

<p>Talks like <a href="https://talks.datenspuren.de/ds24/speaker/MTTWF8/">Neil Walfields</a> <a href="https://talks.datenspuren.de/ds24/talk/JVWRHD/">one</a> (<a href="https://media.ccc.de/v/ds24-422-sequoia-pgp-a-not-quite-new-implementation-of-openpgp">video</a>) would be useful once a year like some sort of yearly safety instruction at work to refresh the PGP knowledge. BUT with a light on the horizon out of the GPG jungle.</p>

<p><a href="https://sequoia-pgp.org/">SequioaPGP</a> is a GPG replacement aiming for simplicity, secure by default but extensible where needed.</p>

<h2>Travel report from the media jungle<a id='travel-report'/></h2>

<p><a href="https://talks.datenspuren.de/ds24/talk/ZZAPNN/">The talk</a> (<a href="https://media.ccc.de/v/ds24-403-reisebericht-aus-dem-mediendschungel">video</a>) held by <a href="https://talks.datenspuren.de/ds24/speaker/7LYEJB/">Xyrill</a> encouraged everyone to participate publicly within media where possible. It is easier to talk more than less. Publish media and work with journalists is both raising the self-efficacy such as making the world to a better place.</p>

<p>Within the talk, some takes were given why press seem to be biased sometimes:</p>

<ul>
<li>advertisement, brand/company loyalty</li>
<li>people/companies strive to consistent world views</li>
<li>people want to raise their social status</li>
<li>availability-heuristics: media can only publish information they get</li>
</ul>

<p>book recommendation: <a href="https://www.goodreads.com/book/show/12617.Manufacturing_Consent">Manufacturing Consent: The Political Economy of the Mass Media by Edward S. Herman and Noam Chomsky</a></p>

<h2>Lock picking village - workshop<a id='lock-picking'/></h2>

<p><img src="datenspuren-24_lockpicking.jpg"/></p>

<p>We learned a lot about lock picking in this workshop and even tried ourselves with some simple pad-locks.</p>

<p>In the beginning we started with a tension wrench and a rake pick. The former is used to apply tension onto the lock and to rotate it when the pins are positioned properly. The later has a couple of bumps and is used to push down the pins randomly by quickly sliding it in and out within the lock. We had the first lock open within the first five minutes of trying. That feeling was satisfying!</p>

<p>The next step was to use a hook pick instead of the rake one. Each pin needed to be pushed down separately with the proper tension applied with the tension wrench. Pushing down not enough or too much will block an unlock. This method works as the pins are not aligned in a straight line due to manfacturing tolerance. There is an order of pins blocking the unlock. Pushing down the pins in the right order will unlock the lock. I didn&rsquo;t accomplish it. But as the raketing was so satisfying and fun, I acquired myself my own set of tools right at the workshop.</p>

<h2>Linux Hello World with hex editor<a id='hex-hello-world'/></h2>

<p><a href="https://talks.datenspuren.de/ds24/speaker/G3PMUT/">Katzenmann</a> held my personal guilty pleasure <a href="https://talks.datenspuren.de/ds24/talk/BQBNYV/">talk</a> (<a href="https://media.ccc.de/v/ds24-394-linux-hello-world-nur-mit-einem-hex-editor">video</a>) of this event. It was about writing hello world within hex hand crafting the binary format <a href="https://www.man7.org/linux/man-pages/man5/elf.5.html">ELF</a> while writing the actual hello-world code in x86_64 code.</p>

<p><img src="datenspuren-24_helloworld.jpg"/></p>

<h3>hexylon<a id='hexylon'/></h3>

<p>This talk motivated me to design a file format describing binary files with hex values along with documentation to maintain readability. It&rsquo;s called <a href="https://github.com/RaphaelPour/hexylon/tree/main">hexylon</a> and a hello world inspired by Katzenmann&rsquo;s looks like this:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">/* ELF Header */
</span></span><span class="line"><span class="cl">0x7f 0x45 0x4c 0x46        // ELF magic number
</span></span><span class="line"><span class="cl">0x02 0x01 0x01 0x03        // version, ABI and endianess stuff
</span></span><span class="line"><span class="cl">00 00 00 00 00 00 00 00    // padding
</span></span><span class="line"><span class="cl">02 00                      // file type
</span></span><span class="line"><span class="cl">0x3e 00                    // Instruction set
</span></span><span class="line"><span class="cl">01 00 00 00                // ELF version
</span></span><span class="line"><span class="cl">78 10 40 00 00 00 00 00    // entry point: sizeof(ELF header) + sizeof(program header)
</span></span><span class="line"><span class="cl">40 00 00 00 00 00 00 00    // ?
</span></span><span class="line"><span class="cl">00 00 00 00 00 00 00 00    // 
</span></span><span class="line"><span class="cl">00 00 00 00                //
</span></span><span class="line"><span class="cl">40 00                      // ELF header size
</span></span><span class="line"><span class="cl">38 00                      // program header entry size
</span></span><span class="line"><span class="cl">01 00                      // program header entry count
</span></span><span class="line"><span class="cl">00 00 00 00 00 00          // unused section stuff
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">/* Program header */
</span></span><span class="line"><span class="cl">01 00 00 00                // entry type (LOAD)
</span></span><span class="line"><span class="cl">05 00 00 00                // section permissions RWX, W+X = 3+2 = 5
</span></span><span class="line"><span class="cl">00 00 00 00 00 00 00 00    // offset (no offset)
</span></span><span class="line"><span class="cl">00 10 40 00 00 00 00 00    // virtual memory address
</span></span><span class="line"><span class="cl">00 00 40 00 00 00 00 00    // physical memory address (where needed)
</span></span><span class="line"><span class="cl">ac 00 00 00 00 00 00 00    // size in file
</span></span><span class="line"><span class="cl">ac 00 00 00 00 00 00 00    // size in memory
</span></span><span class="line"><span class="cl">00 10 00 00 00 00 00 00    // alignment
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">/* Program */
</span></span><span class="line"><span class="cl">b8 01 00 00 00             // sys_write
</span></span><span class="line"><span class="cl">bf 01 00 00 00             // arg0: stdout
</span></span><span class="line"><span class="cl">48 0xbe                    // arg1: mov rsi
</span></span><span class="line"><span class="cl">0x9f 10 40 00 00 00 00 00  // virtual memory address of string
</span></span><span class="line"><span class="cl">ba                         // mov edx
</span></span><span class="line"><span class="cl">0x0d 00 00 00              // arg2: string length
</span></span><span class="line"><span class="cl">0x0f 05                    // call syscall
</span></span><span class="line"><span class="cl">b8 0x3c 00 00 00           // sys_exit
</span></span><span class="line"><span class="cl">0xbf 00 00 00 00           // arg0: exit code
</span></span><span class="line"><span class="cl">0x0f 05                    // call syscall
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">/* data */
</span></span><span class="line"><span class="cl">68 65 0x6c 0x6c 0x6f 20    // &#34;hello &#34;
</span></span><span class="line"><span class="cl">77 0x6f 72 0x6c 64 21 0x0a // &#34;world!\n&#34;
</span></span></code></pre>
<p>This was so much fun. Thanks for the motivation!</p>

<h2>Speedhacking<a id='speedhacking'/></h2>

<p><a href="https://media.ccc.de/v/ds24-367-die-erste-speedhacking-show-der-welt">The speedhacking show</a> was an entertaining specatle. I didn&rsquo;t even know how much fun it would be watching people replacing hard disks, installing operating systems or solder with lighters as a challenge.</p>

<h2>The event<a id='the-event'/></h2>

<p>I personally underestimated the value of a commerce-free opportunity to share ideas and knowledge about technology and how they affect society. This was a human-centric positive experience where I felt welcome in terms of my neurodivergence.</p>

<p>It was also enlighting to get in touch with the queer-community and be in a place where people can be people. The event helped be to lower unfounded inhibitions.</p>

<h2>Souvenirs and future rabbit holes<a id='souvenirs'/></h2>

<p><img src="datenspuren-24_souvenirs.jpg"/></p>

<ul>
<li>build a ferris split keyboard (<strong>Update:</strong> <a href="https://evilcookie.de/ferris-sweep-split-keyboard-build.html">I built it</a> \o/)</li>
<li>writing executable binaries by hand</li>
<li>try out sequoiaPGP</li>
<li>lock picking as replacement for fidget cubes</li>
<li>attend more ccc events</li>
</ul>

<h2>DD Impressions<a id='dd-impressions'/></h2>

<p>Finally I want to share some impressions from Dresden which I took with my DSLR.</p>

<p><img src="datenspuren-24_i1.jpg"/>
<img src="datenspuren-24_i2.jpg"/>
<img src="datenspuren-24_i3.jpg"/>
<img src="datenspuren-24_i4.jpg"/>
<img src="datenspuren-24_i5.jpg"/></p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 23 Sep 2024 21:21:40 +0200</pubDate>
    </item>
    <item>
      <title>writing blog posts - done is better than perfect</title>
      <link>https://evilcookie.de/writing-blog-posts---done-is-better-than-perfect.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Writing blog posts - done is better than perfect</h1>

<p>I had a lot of blogs since I have access to the internet. Mostly unsuccessful in terms of continuously writing new posts.</p>

<p>What is different with <code>$this</code> one?</p>

<h2>principles</h2>

<p>As stated in my <a href="https://evilcookie.de/hello-internet.html">first post</a>, I started with the following principles:</p>

<blockquote>
<ul>
<li>focus: CLI-only, no distractions</li>
<li>simplicity: only the features currently needed</li>
<li>minimalism: focus on content and not style</li>
</ul>
</blockquote>

<p>Later on I discovered that polishing, fixing typos and similar cosmetic tasks got me stuck in my flow. Focus is a hard topic for me,
and so is keeping up the motivation for reprocessing a text multiple times. In my dreams, I write posts like a diary without
thinking to much, words just bubble out. Like this post.</p>

<p>This is some writer freedom I started to enjoy once I accepted the imperfectionism.</p>

<h2>experience</h2>

<p>People have no interest in my blog. The discussion board is empty and the count of people approaching me is rather small. I even know everyone. But, that&rsquo;s ok. This is my journey and kind of a finish for some side projects I&rsquo;m working on.
Sometimes I go through my older posts and smile about the places I&rsquo;ve been and experience I gained. THAT is a real motivation to continue writing rather than hoping for some clicks or interactions. I guess those were the reasons why
older blogs didn&rsquo;t work pretty well.</p>

<p>Despite that, my writing abilities got better and just getting started is easier than ever.</p>

<h2>vision</h2>

<p>Continue.</p>

<p><small style="color:rgba(0,0,0,0)">+hf</small></p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 26 Aug 2024 12:19:41 +0200</pubDate>
    </item>
    <item>
      <title>home office with mobile data</title>
      <link>https://evilcookie.de/home-office-with-mobile-data.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Home office via hot spot</h1>

<p><img src="home-office-with-mobile-data_monitoring.jpg"/></p>

<p>tl;dr Working from home via hot spot isn&rsquo;t as unreliable and traffic expensive as I thought. Pre-schedule suitable work and delay data intensive ones like meetings help along the way.</p>

<p>I recently moved into a new flat and the technician appointment to enable my internet connection was still in the future. At the same time I awaited
some furniture deliveries and you know how they&rsquo;re scheduled in Germany<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>: <em>expected delivery time between 7 and 13 o&rsquo;clock</em>.</p>

<p>To save my vacation for actual holiday, I got the idea of working from home and connecting my notebook with the hot spot of my mobile.</p>

<h2>Limits</h2>

<p>My mobile data plan is limited to 10GB where 5GB are already spent. Clearly if I pull some containers or install some updates, the
remaining traffic won&rsquo;t last long. Even building go binaries may come with a surprise as missing dependencies get downloaded automatically.</p>

<p>So this is a matter of preparing the right work and estimate the data needs properly. Audio- and video chat is hard to estimate for me, it&rsquo;s intuitively data hungry
but compression algorithms got better in the past years.</p>

<h2>Preparation</h2>

<p>There were some TODO&rsquo;s where I could work on locally and watch ci pipelines via some neat git-platform-integration tools (e.g. <a href="https://cli.github.com/">github</a>, <a href="https://docs.gitlab.com/ee/editor_extensions/gitlab_cli/">gitlab</a>,&hellip;).
Meetings were only scheduled in the afternoon with the hope that the delivery already arrived and I had the time to drive to the office.</p>

<h2>Home office</h2>

<p>I started at 6 o&rsquo;clock and monitored my consumption using the android lock screen widget for hotspots (see featured image above). I worked on some pipelines, monitored its jobs using proper integration which worked pretty well without consuming that much data. Even opening the git-platform e.g. view Pull Request worked well. Some web-based tools don&rsquo;t need much, other consumed 10 megs on loading. Such learnings are helpful to categorize workloads into data-friendly and data-hungry ones.</p>

<p>When working on servers via ssh, I tried to use pagers like <a href="https://linux.die.net/man/1/less"><code>less</code></a><sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> to control the amount of output sent to my screen, as much as possible.</p>

<p>The bell rang at 8:30 with the delivery of my bed, so I worked til 9 and drove to the office. I consumed about 77.34MB in those three hours of work. I had expected at least ten times more.</p>

<h2>Summary</h2>

<p>Those three hours of working via mobile data went very well. Git and git-platform-integrations work well without needing much data. Some web-based tools are
hungry which need to be kept in mind.</p>

<p>Definitely something I want to do again to gain more experience.</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Probably you don&rsquo;t :D You get/make out a date and the deliverer comes anytime in the day. Sometimes you get a two hour time window, sometimes they give you a call half an hour earlier.</li>

<li id="fn:2">Since I haven&rsquo;t any stocks in this one, there are surely more out there: <a href="https://linux.die.net/man/1/more"><code>more</code></a>, <a href="https://github.com/tstack/lnav"><code>lnav</code></a> and if you&rsquo;re a fan of ed, combinations of <a href="https://linux.die.net/man/1/head"><code>head</code></a> and <a href="https://linux.die.net/man/1/tail"><code>tail</code></a> might also do the job.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 23 Aug 2024 12:30:38 +0200</pubDate>
    </item>
    <item>
      <title>Bash-cheat sheet</title>
      <link>https://evilcookie.de/bash-cheat-sheet.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Bash - cheat sheet</h1>

<h3>Contents</h3>

<ul>
<li><a href="#arguments">Arguments</a></li>
<li><a href="#brace-expansion">Brace Expansion</a></li>
<li><a href="#colors">Colors</a></li>
<li><a href="#conditionals">Conditionals</a></li>
<li><a href="#debugging">Debugging</a></li>
<li><a href="#pipes-and-redirects">Pipes and Redirects</a></li>
</ul>

<h2>Arguments</h2>

<table>
<thead>
<tr>
<th>variable</th>
<th>description</th>
</tr>
</thead>

<tbody>
<tr>
<td><code>$0</code></td>
<td>name of the script</td>
</tr>

<tr>
<td><code>$1</code></td>
<td>first argument</td>
</tr>

<tr>
<td><code>$2</code></td>
<td>second argument</td>
</tr>

<tr>
<td><code>$&lt;n&gt;</code></td>
<td><code>&lt;nth&gt;</code> argument, where <code>n &gt; 0</code></td>
</tr>

<tr>
<td><code>$@</code></td>
<td>all arguments as one string</td>
</tr>

<tr>
<td><code>$#</code></td>
<td>count of arguments</td>
</tr>
</tbody>
</table>

<h3>Example</h3>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> script started with <span class="nv">$#</span> args: <span class="nv">$@</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> arg in <span class="s2">&#34;</span><span class="nv">$@</span><span class="s2">&#34;</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$arg</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="cl"><span class="c1"># $ ./script.sh --config=test --verbose 1 2</span>
</span></span><span class="line"><span class="cl"><span class="c1"># script started with 4 args: --config=test --verbose 1 2</span>
</span></span><span class="line"><span class="cl"><span class="c1"># --config=test</span>
</span></span><span class="line"><span class="cl"><span class="c1"># --verbose</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 1</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 2</span>
</span></span></code></pre>
<h2>Brace Expansion<a id='brace-expansion'/></h2>

<ul>
<li><code>touch {index,blog}.{html,css}</code>:

<ul>
<li>expands the two braces to any combination</li>
<li>final command: <code>touch index.html index.css blog.html blog.css</code></li>
<li>no whitespaces allowed</li>
</ul></li>
<li><code>touch {1..3}.dat</code>:

<ul>
<li>expands to numbers inclusive from start to end with step size one</li>
<li>final command: <code>touch 1.dat 2.dat 3.dat</code></li>
</ul></li>
</ul>

<h2>Colors</h2>

<p>Print the rainbow: <code>for (( i = 0; i &lt; 39; i++ )); do echo -ne &quot;\033[0;&quot;$i&quot;m Normal: (0;$i); \033[1;&quot;$i&quot;m Light: (1;$i)\t\t\t\t\t&quot;; done</code><sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></p>

<p><img src="bash-cheat-sheet_colors.png"/></p>

<p>Prefix <code>\033</code> is preferable over <code>\x1b</code> and <code>\e</code>, as its supported on more platforms.</p>

<h2>Conditionals</h2>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span><span class="o">[</span> &lt;CONDITION&gt; <span class="o">]</span><span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">  ...
</span></span><span class="line"><span class="cl"><span class="k">elif</span> <span class="o">[</span><span class="o">[</span> &lt;CONDITION&gt; <span class="o">]</span><span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">  ...
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">  ...
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span></code></pre>
<table>
<thead>
<tr>
<th>condition</th>
<th>description</th>
</tr>
</thead>

<tbody>
<tr>
<td><code>&quot;$VAR&quot; == &quot;STRING&quot;</code></td>
<td>compare content of env var with string</td>
</tr>

<tr>
<td><code>-z &quot;$VAR&quot;</code></td>
<td>test if string length is zero</td>
</tr>

<tr>
<td><code>-n &quot;$VAR&quot;</code></td>
<td>test if string length is not zero</td>
</tr>

<tr>
<td><code>-f &quot;$VAR&quot;</code></td>
<td>test if regular file exist</td>
</tr>
</tbody>
</table>

<h2>Debugging</h2>

<ul>
<li><code>set -x</code>: print output of each pipeline step</li>
</ul>

<h2>Pipes and Redirects<a id='pipes-and-redirects'/></h2>

<ul>
<li><code>command1 | command2</code>: Write stdout of <code>command1</code> to stdin of <code>command2</code></li>
<li><code>command1 &gt; file</code>: Write stdout of <code>command1</code> to file overwriting</li>
<li><code>command1 &gt;&gt; file</code>: Append stdout of <code>command1</code> to file</li>
<li><code>command1 &gt; file 2&gt;&amp;1</code>: Pipe stderr to stdout, append combined output to file</li>
<li><code>command1 &lt;&lt;&lt; &quot;${VAR}&quot;</code>: use content of env var as stdin, similar to <code>echo ${VAR}|command1</code></li>
</ul>

<p>Write multi-line text to <code>file</code>. <code>EOF</code> is an arbitrary delimiter:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">cat &lt;&lt;EOF &gt;&gt; file
</span></span><span class="line"><span class="cl">[Section]
</span></span><span class="line"><span class="cl">    key=value
</span></span><span class="line"><span class="cl">    another_key=3.14
</span></span><span class="line"><span class="cl">EOF
</span></span></code></pre>
<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Inspired from <a href="https://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux#comment57867742_5947802">SO</a></li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 23 Jul 2024 12:33:18 +0200</pubDate>
    </item>
    <item>
      <title>Getting old</title>
      <link>https://evilcookie.de/getting-old.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Getting old</h1>

<p><img src="getting-old_getting_old.png"/></p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 22 Jul 2024 12:30:30 +0200</pubDate>
    </item>
    <item>
      <title>GopherCon 2024</title>
      <link>https://evilcookie.de/gophercon-2024.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>GopherCon Europe 2024</h1>

<p><img src="gophercon-2024_gophercon.jpg"/></p>

<p>I attended the GopherCon Europe 2024 in Berlin<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> to check out the latest GOssip<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>.</p>

<p>Some data:</p>

<ul>
<li>date: 17.05. - 20.05.</li>
<li>location: <a href="https://www.alte-muenze-berlin.de/">Alte Münze Berlin</a></li>
<li>two tracks</li>
<li>accidental pictures with the Go Team: (<a href="https://nitter.lucabased.xyz/blockciphertext/status/1803429319672246494#m">1</a>) (<a href="https://nitter.lucabased.xyz/TolyPash/status/1803428346673398029#m">2</a>)</li>
<li><a href="https://gopherconeurope.substack.com/">Website</a></li>
</ul>

<h3>Contents</h3>

<ol>
<li><a href="#go-business">The Business of Go</a></li>
<li><a href="#ddd">Rethinking domain-driven design</a>

<ul>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#idea1">Idea 1 - always keep valid state in memory</a></li>
<li><a href="#idea2">Idea 2 - keep domain-logic database-agnostic</a></li>
<li><a href="#idea3">Idea 3 - reflect your business logic internally literally</a></li>
</ul></li>
<li><a href="#panel">Go Team Panel</a></li>
<li><a href="#podcast">GoTime Podcast</a></li>
<li><a href="#http-workout">HTTP Routing</a></li>
<li><a href="#recommendations">Recommendations</a></li>
<li><a href="#impressions">Impressions</a></li>
</ol>

<h2>The business of Go<a id='go-business'/></h2>

<p>The Go Product Lead from Google <a href="https://github.com/cameronbalahan">Cameron Balahan</a> gave some insights into googles perspective and motivations about go.</p>

<ul>
<li>google spots trends and pushes suitable features</li>
<li>go developer success = google success</li>
<li>strong in cloud, cloud-native solutions are mostly go (docker, kubernetes,&hellip;)</li>
<li>different types of dev target groups: inventors, early adopters, late adopters, <insert last group here></li>
</ul>

<h2>Rethinking domain-driven design<a id='ddd'/></h2>

<p>The principal engineer <a href="https://github.com/roblaszczak">Robert Laszczak</a> from <a href="https://www.slashid.dev/">/ID</a> talked about <a href="https://en.wikipedia.org/wiki/Domain-driven_design">Domain-Driven Design</a> (short: DDD).</p>

<h3>Introduction<a id='introduction'/></h3>

<p>DDD is about encapsulating business logic into separate coherent/independent components instead of having one chunk of logic. The motivation is to avoid accidental complexity that comes with entangling multiple domains with another. There are
manifold ways of implementing this concept after identifying several domains within a codebase that could be separated. Usually they all have in common that the external interface is generic enough that the internals can be swapped easily. Wherever those components are implemented within different micro services or go structs that encapsulate the inner logic in private.</p>

<p>This reminds me of the basics of <a href="https://en.wikipedia.org/wiki/Object-oriented_programming">Object Oriented Programming</a> (short OOP), where data and code is encapsulated within a class. The external interface provides an abstraction and ideally the caller doesn&rsquo;t need to know how the class-specific problem is solved.</p>

<p>Robert also stated that DDD is not the ultimate solution for everything. Especially for small code bases it&rsquo;s usually overhead and lead to overengineering.</p>

<h3>Idea 1 - always keep valid state in memory<a id='idea1'/></h3>

<p>Use private struct fields and public methods to control the access and especially modification of the inner state to ensure the inner state is always valid.</p>

<p>E.g. a struct <code>Person</code> providing an age, should ensure its not negative. This can be accomplished by only setting the age within the constructor <code>func NewPerson(name string, age int) (Person, error)</code> with a validation beforehand. If the validation fails, the constructor fails (age &lt; 0) with an error.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="kd">struct</span> <span class="nx">Person</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl">  <span class="nx">age</span>  <span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">NewPerson</span><span class="p">(</span><span class="nx">name</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">age</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="nx">Person</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nx">age</span> <span class="p">&lt;</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">Person</span><span class="p">{</span><span class="p">}</span><span class="p">,</span> <span class="nx">errors</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="s">&#34;age must &gt;=0&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">Person</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="p">:</span> <span class="nx">name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">age</span><span class="p">:</span> <span class="nx">age</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Getters do also have another usage than just provide access to private variables. They can calculate values on the fly that would be otherwise likely to get outdated.</p>

<p>E.g. in order to have the correct age of an user, at any time, it would be easier to store the year of birth than the age. A getter <code>func (p Person) Age() int</code> then gets the current year and calculates the age on-demand, instead of storing it within the struct, doomed to get outdated<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="kd">struct</span> <span class="nx">Person</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span>        <span class="kt">string</span>
</span></span><span class="line"><span class="cl">  <span class="nx">yearOfBirth</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">p</span> <span class="nx">Person</span><span class="p">)</span> <span class="nf">Age</span><span class="p">(</span><span class="p">)</span> <span class="kt">int</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="nf">Year</span><span class="p">(</span><span class="p">)</span> <span class="o">-</span> <span class="nx">p</span><span class="p">.</span><span class="nx">yearOfBirth</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<h2>Idea 2  - keep domain-logic database-agnostic<a id='idea2'/></h2>

<p>Well, the title says it all. Business logic and storage layer should be abstract enough to be interchangeable. This prevents salami-code where domain- and storagecode is entangled  into another.</p>

<p>Go&rsquo;s Interfaces are a perfect fit for this, defining an external set of functions that some type needs to satisfy.</p>

<p>E.g. a simple  <a href="https://en.m.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> storage backend of a person could look like this:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">interface</span> <span class="nx">Storage</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">Get</span><span class="p">(</span><span class="nx">name</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="nx">Person</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">Add</span><span class="p">(</span><span class="nx">p</span> <span class="nx">Person</span><span class="p">)</span> <span class="kt">error</span>
</span></span><span class="line"><span class="cl">  <span class="nf">Update</span><span class="p">(</span><span class="nx">name</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">age</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>In order to get an prototype fast, the first backend could be implemented using a file. As data grows this backend could be replaced with a sqlite db. You discovered that a key-value db fits better and implement a redis/valkey backend. Whatever storage backend is used, the layer above using a backend via the storage interface can stay the same throughout the storage journey.</p>

<h2>Idea 3 - Reflect your business logic internally literally<a id='idea3'/></h2>

<p>Interesting take about simplifying requirements engineering and requirement validation with non-technical stakeholder or user of the application. Write the struct field and types as close to the formular feature definition as possible. Non-technical people might find this easier to read as.</p>

<p>For example: <em>A person should have a firstname and lastname such as a year-of-birth. It can also have documents attached, if any.</em></p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="nx">firstname</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl"><span class="nx">lastname</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">yearOfBirth</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">documents</span> <span class="p">[</span><span class="p">]</span><span class="nx">Document</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<h2>Go Team Panel<a id='panel'/></h2>

<p>Four members of the Go Team answered questions from the crowd:</p>

<ul>
<li><a href="https://github.com/jba">Jonathan Amsterdam</a>:</li>
<li><a href="https://www.linkedin.com/in/zvonimir-pavlinovic-505b7531">Zvonimir Pavlinovic</a></li>
<li><a href="https://research.google/people/alice-merrick/">Alice Merrick</a></li>
<li><a href="https://github.com/cameronbalahan">Cameron Balahan</a></li>
</ul>

<p>Questions:</p>

<ul>
<li>Is it hard to make Go simple?

<ul>
<li><em>Cameron</em>: No, once the overengineered solutions from early go were solved.</li>
<li><em>Jonathan</em>: Conservative about new features make lives easier.</li>
</ul></li>
<li>Whats next about generics?

<ul>
<li>generic type aliases</li>
<li>implementing go generics all over the standard lib</li>
</ul></li>
<li>Regret design descisions? The for loop, therefore the language change.</li>
<li>When will enums in go be implemented?

<ul>
<li><em>Jonathan</em>: No easy way to implement.</li>
<li><em>Alice</em>: Many requests but less use-cases.</li>
</ul></li>
<li>Will there ever be go2? No, since compatibility is already controllable via mod file</li>
<li>Will there be memory arenas? Maybe, no easy way to prevent panic after bad free</li>
<li>Will there be nil-safety?

<ul>
<li><em>Cameron</em>: Not near soon.</li>
<li><em>Jonathan</em>: Nil-safety only moves the problem to another, less debugable, domain. Without nil-safety, bugs appear exactly at the line where they have been triggered.</li>
</ul></li>
<li>Ternary operator? Nope.</li>
<li>Slog WithContext functions? Probably not, as there is no general way of implementing it. Everyone should implement it by themselve.</li>
<li>AndroidSDK? Nope, use Kotlin.</li>
<li>Currency support? No, use 3rd-party libs.</li>
<li>What are init functions for? Initialize variables where one line is not enough readability-wise.</li>
<li>Immutable values? Data-race freedom must be ensured first.</li>
<li>Zero functions i.e. default methods for interfcaces? Complicated.</li>
<li>Generic sync.pool? Use a wrapper</li>
</ul>

<h2>GoTime Podcast<a id='podcast'/></h2>

<p><img src="gophercon-2024_gotime.jpg"/></p>

<p>An episode of the <a href="https://changelog.com/gotime](https://changelog.com/gotime/320)">GoTime Podcast</a> with GopherCon moderator and podcast host Mat Ryer got recorded at the end of the first day. Some speakers played against each other ranking the
answers of a local go survey.</p>

<h2>HTTP Routing enhancements<a id='http-routing'/></h2>

<p>Go Team member <a href="https://github.com/jba">Jonathan Amsterdam</a> talked about the recent pattern routing feature in the standard lib <code>net/http</code> and its challenges. To this feature,
route matcher could only be literal without any variables or wildcards in it.</p>

<ul>
<li>balance between expressiveness and complexity</li>
<li><code>mux.Hanle(&quot;GET /resource&quot;, handlerFunction)</code> works now</li>
<li>use <code>{id}</code> for wildcard</li>
<li>use <code>{$}</code> to match the end of a string</li>
<li>method can be contained within the route, 405 will be returned if method doesn&rsquo;t match</li>
<li>simple rules for precedence so far:

<ul>
<li>host over no host</li>
<li>longest path wins</li>
<li>registration order doesn&rsquo;t matter</li>
</ul></li>
<li>problem with new wildcards: longest path depends on the wildcards =&gt; subset gets presedence, conflicts result in error</li>
<li>conflict: two routes intersect or are fully equal</li>
<li>rethink problem in a semantic manner rather than a syntactical one</li>
<li>implement 80% of the features/use-cases to keep simplicity</li>
<li>only a small fraction of regex used</li>
<li>use maps to keep pattern conflict lookup &lt; O(n²)</li>
<li>stdlib functions should be faster than <code>O(n²)</code></li>
</ul>

<h2>Recommendations<a id='recommendations'/></h2>

<p>Talking with people at conferences always results in a list of recommendations. Some are reasonable, other might be random:</p>

<ul>
<li>play <a href="https://en.wikipedia.org/wiki/Monkey_Island">monkey island 1+2</a> with <a href="https://www.scummvm.org/">ScummVM</a></li>
<li><a href="https://en.wikipedia.org/wiki/The_Settlers">Siedler 1</a></li>
<li>checkout the Go Web Framework <a href="https://www.arrower.org/">arrower</a>, shout out to the contributor Tobias!</li>
<li>make ravioli yourself</li>
<li>collect mushrooms in the woods</li>
<li><a href="https://pragprog.com/titles/dnvim2/practical-vim-second-edition/">Practical Vim</a></li>
<li><a href="https://en.m.wikipedia.org/wiki/Lucifer_(TV_series)">Luzifer</a>, <a href="">The Expance</a></li>
<li><a href="https://ziglang.org/">Zig</a></li>
</ul>

<h2>Impressions</h2>

<p><img src="gophercon-2024_blogedit.jpg"/>
<small>Me starting <code>$this</code> blog post using my notes.</small></p>

<p><img src="gophercon-2024_screen.jpg"/>
<small>Huge LCD screen at track 1.</small></p>

<p><img src="gophercon-2024_football.jpg"/>
<small>The <a href="https://www.uefa.com/euro2024/">European Championship 2024</a> took place in parallel of the GopherCon. Luckily they decided to stream the game &ldquo;Germany - Hungary&rdquo; onto the largest screen I ever saw \o/</small></p>

<p><img src="gophercon-2024_swag.png"/>
<small>Got myself a fluffy gopher and some stickers.</small></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">as part of the Hetzner Cloud Instance Team.</li>

<li id="fn:2">shameless pun intended :D</li>

<li id="fn:3">Caching-wise, it would also make sense to cache such values that don&rsquo;t often change e.g. to accelerate requests.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 19 Jun 2024 13:59:48 +0200</pubDate>
    </item>
    <item>
      <title>working on the road-self experiment</title>
      <link>https://evilcookie.de/working-on-the-road-self-experiment.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>working on the road - self experiment</h1>

<p><img src="working-on-the-road-self-experiment_brandenburgertor.jpeg"/></p>

<p>tl;dr: Self experiment about working on the road. It&rsquo;s challenging but opens
up new possibilities. I worked in the train and within a coffee.</p>

<p>My productive comfort zone is behind a desk within an office having sparing
partners for sharing and discussing ideas. Need more focus? Noise canceling
headphones to the rescue!</p>

<p>But as time flies, work environments change and even with fully remote options
or colleagues new environments spawn. New challenges arise. How to connect to
fully remote collegues? How do they feel, sitting alone on their desks most of
the time? What opportunities emerge if I open up myself working from somewhere else than just the office?</p>

<h3>Contents</h3>

<ol>
<li><a href="#covid">Covid</a></li>
<li><a href="#motivation">Motivation</a></li>
<li><a href="#experiment">The experiment</a></li>
<li><a href="#challenges">Challenges</a>

<ul>
<li><a href="#find-table">Finding a table</a></li>
<li><a href="#noisy-neighbors">Noisy neighbors</a></li>
<li><a href="#change-trains">Change trains</a></li>
<li><a href="#focus">Focus</a></li>
<li><a href="#mobile-distractions">Mobile distraction</a></li>
</ul></li>
<li><a href="#bonus">Bonus: Working within a coffee</a></li>
<li><a href="#summary">Summary</a></li>
</ol>

<h2>Covid<a id='covid'/></h2>

<p>Within covid, I was the only one left in the data center as local contact person
in case immediate action was needed. I refused to work from home as I needed this
contrast within the office to be productive and to avoid distractions more
easily.</p>

<p>I got used to tools like mumble, whereby, zoom, jitsi and we quickly learned the
pros/cons such as ups and downs of having only active communication. Active like
one person needs a subject to start a conversation while it was hard to just
replicate the office where you can jump into a dialog that takes place around
you. Yes, you can always be online in one channel with all the others, but that
also challenges my focus. This works for other teams pretty well, having one broadcast room.</p>

<p>I needed to get use of discussing ideas actively and over the wire.</p>

<p>Two years within the pandemic with streaks over several months without
seeing anyone else in the data center, I felt the need of change.</p>

<h2>Motivation<a id='motivation'/></h2>

<p><em>Change yourself before the change comes to you<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></em></p>

<p>Within covid it was only a matter of time before our first fully-remote
colleague joins the team. Other teams already opened up for remote work and it was fare more easy for recruitment
to offer this benefit working from home. Having an open and fruitful office culture full of construtive discussions, I asked myself how this might change having fully remote colleagues. How do they feel alone at home? How does the environment affect the productivity? I was curious about the new challenges we might get.</p>

<p>Time management-wise, doing home office cuts the time for getting to the work place
simplifies appointments. Like when the spedition tells you they come by with the
new sofa between 7am and 6pm&hellip;</p>

<p>New visions arise:</p>

<ul>
<li>taking a nap after lunch</li>
<li>getting a Friday croissant from the bakery for breakfast</li>
<li>ordering furniture with unreliable delivery time</li>
<li>save time and go early on going on a trip</li>
<li>focus on complex matter</li>
<li>working in completely different work environments in co-working spaces,
parents, friends,&hellip;</li>
</ul>

<p>I wasn&rsquo;t ready for this, but I wanted to give it a try. So I worked four weeks
from home. I was tired, four hours felt like eight. My back hurt due to my
unergonomic desk and desk-chair. On the other side, I could simply go out of my
working room to leave the work context.</p>

<p>I bought a better desk-chair and a standing desk, changed rooms to make the work
place more &ldquo;home-office-native&rdquo;. It changed a lot. Now I do home-office on every
Friday, it feels like a ritual.</p>

<p>Next step is to work from the road.</p>

<h2>The experiment<a id='experiment'/></h2>

<p><img src="working-on-the-road-self-experiment_train.jpeg"/></p>

<p>I&rsquo;m currently traveling to Berlin<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> and thought it would be a nice opportunity to test this out by writing a blog
article about it. My goal: finish the article before arriving at the
destination.</p>

<h2>Challenges<a id='challenges'/></h2>

<h3>Finding a table<a id='find-table'/></h3>

<p>It starts with finding a table with power outlet, as my 10yr old mac book&rsquo;s
battery is crap. I quickly scanned the train as it arrived and found a neat one.</p>

<h3>Noisy neighbors<a id='noisy-neighbors'/></h3>

<p>I like to socialize with others and give everyone his personal space as I would
like it myself. But yeah, you never know what you get. I wasn&rsquo;t traveling
alone but setting limits helped. Noise-cancelling headphones are also key having
neighbors doom-scrolling tik-tok with audio on loudspeaker.</p>

<p>On the other side are conversation good distractions to gain focus again. I
called my mom and talked for about an hour.</p>

<h3>Change trains<a id='change-trains'/></h3>

<p>As I&rsquo;m living in a small city without inter-city train connections<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup> and I
travel with the <a href="https://www.bahn.de/angebot/regio/deutschland-ticket">Detuschland-Ticket</a><sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup>, I need to change trains quite often.</p>

<p>Changing trains is stress. Even if trains are on time, you need to pack all your
stuff, walk to the next track, find a new seat (see <a href="#find-table">Find a table</a>)
and get back to work. If trains are not on time, like today<sup class="footnote-ref" id="fnref:5"><a href="#fn:5">5</a></sup>, you need to
keep attention for announcements, refreshing the train app<sup class="footnote-ref" id="fnref:6"><a href="#fn:6">6</a></sup> and consider
alternatives.</p>

<h3>Focus<a id='focus'/></h3>

<p>As with all working environments, focus must be gained and kept up.
Interestingly my neuro-diversity didn&rsquo;t crossed my plans about that but actually
did the opposite I guess. I felt kind of a hyper focus writing about this topic.
Words have flown, sentences emerged, structures got visible.</p>

<h3>Mobile distractions<a id='mobile-distractions'/></h3>

<p>Similar to <a href="#noisy-neighbors">Noisy neighbors</a> challenge but more about the work
and their tools itself. Cut the unnecessary stuff and get straight to the work
unlike my first attempt:</p>

<ol>
<li>create new post via blogctl. Oh no, the blog repo isn&rsquo;t checked out.</li>
<li>No WLAN inside the train, hotspot needs to be turned on, luckily I have a new
provider granting me enough traffic.</li>
<li>Bad bandwidth, pulling takes ages&hellip;</li>
</ol>

<p>I then recognized that I don&rsquo;t need internet to open a new file and just start
writing plain text, as I always do. I just need to transfer it later into my
repo, no problemo.</p>

<p>Sure there tasks that are depend on a connection within my job:</p>

<ul>
<li>working remotely via ssh on a server</li>
<li>git operations with the upstream remote</li>
<li>pulling dependencies for compiling, building code and containers</li>
<li>meetings, video/audio calls with colleagues</li>
</ul>

<h2>Bonus: Working within a coffee<a id='bonus'/></h2>

<p><img src="working-on-the-road-self-experiment_coffee.jpeg"/></p>

<p>Next day, the article was already finished, I though about another expierment within a coffee.</p>

<p>Similar challenges: Internet, noisy neighbors plus you need to spend something.</p>

<p>I enjoyed my place inside looking outside to an intersection full of people in Friedrichshain. I always wanted to work within a coffee on a fancy laptop<sup class="footnote-ref" id="fnref:8"><a href="#fn:8">7</a></sup> sippin on my americano while doing productive stuff. I guess I can make a check mark on that one \o/</p>

<h2>Summary</h2>

<p>From a neuro-diverse perspective, I surfed the productivity wave on writing this
post while riding trains. Structure, words, sentences emerged without
any barrier and made sense immediately. I haven&rsquo;t written for months now, and I
was happy to have something relevant to write about again.</p>

<p>I reached my goal of finishing this article before arriving<sup class="footnote-ref" id="fnref:7"><a href="#fn:7">8</a></sup>.</p>

<p>All the challenges are potential stress factors and need to be considered.
Long connections might help keeping the focus up for a longer period of time. I
guess ICE&rsquo;s with WLan are also more suitable for working on the road.</p>

<p>This self-experiment was fun and I&rsquo;m proud of all the words. It&rsquo;s not easy to
make clear whats hidden behind behavior, feelings or moods. This post helped me
to articulate my prejudices against working on the road and to process some
fears by actually gaining experience.</p>

<p>Greetings from Berlin!<sup class="footnote-ref" id="fnref:9"><a href="#fn:9">9</a></sup></p>

<p><img src="working-on-the-road-self-experiment_dualipa.jpg"/></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">I made this up by myself as I don&rsquo;t remember any quote about that.</li>

<li id="fn:2">going to the Dua Lipa concert \o/</li>

<li id="fn:3">Namely ICE/IC in Germany.</li>

<li id="fn:4">Also called 49EUR-Ticket, allows to travel with all regional and city public transports.</li>

<li id="fn:5">In my case the RE (Regional Express) to Chemnitz was too late for changing to the RB (Regional Bahn), alternatives cost more (since IC&rsquo;s are involved) or take a lot of more time. Luckily RE has a higher priority than RB, so the RB waited for us.</li>

<li id="fn:6">namely <a href="">DB Navigator</a>, everything you need to travel by train in Germany, very handy, gives you push notifications before changing trains and in case plans change.</li>

<li id="fn:8">the one with the fruit, but 10yrs old</li>

<li id="fn:7">Well, aside of typos and the images but <em>Done is better than perfect</em>.</li>

<li id="fn:9">Thanks Paula for the concert impression</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 07 Jun 2024 12:20:40 +0200</pubDate>
    </item>
    <item>
      <title>Chemnitzer Linuxtage 2024</title>
      <link>https://evilcookie.de/chemnitzer-linuxtage-2024.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Chemnitzer Linuxtage 2024</h1>

<p><img src="chemnitzer-linuxtage-2024_clt24.png"/></p>

<p>I attended the <a href="https://chemnitzer.linux-tage.de/2024/en">Chemnitzer Linuxtage 2024</a> and it was great fun<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>:</p>

<ul>
<li>date: 16.03.+17.03.</li>
<li>6 lecture halls</li>
<li><a href="https://chemnitzer.linux-tage.de/2024/en/programm/vortraege">lectures (german only</a></li>
<li>regular ticket price: 12€</li>
<li>workshop price: 5€</li>
</ul>

<p><strong>Disclaimer</strong> as within my <a href="https://evilcookie.de/we-are-developers-world-congress-2022.html">last conference</a>: I’m paraphrasing (italic) the speaker based on my notes and memories as best as I can.</p>

<h3>Content</h3>

<ul>
<li><a href="#analog">Analoge Fotos mit freier Software digitalisieren</a></li>
<li><a href="#chat-gpt">Wie funktioniert ChatGPT?</a></li>
<li><a href="#rocket-lang">RocketLang - Mein eigener kleiner BER</a></li>
<li><a href="#compiler">Der Compiler: Eine Einführung für Anfänger</a></li>
<li><a href="#mini-llm">Mini-LLM selbst gemacht</a></li>
<li><a href="#open-source">(Fast) alles was man an der Uni nicht lernt</a></li>
<li><a href="#j-workshop">J Workskop</a></li>
<li><a href="#sticker">Sticker</a></li>
</ul>

<h2>Analoge Fotos mit freier Software digitalisieren<a id='analog'/></h2>

<p>The kernel developer <a href="https://github.com/mmind">Heiko Stübner</a> held a <a href="https://chemnitzer.linux-tage.de/2024/en/programm/beitrag/223">talk</a> (<a href="https://media.ccc.de/v/clt24-223-analoge-fotos-mit-freier-software-digitalisieren#t=2808">video</a>) about
digitalizing analog photos using free software. Since I&rsquo;m a hobby photographer (<a href="https://evilcookie.de/blog-update-customization.html">see</a> <a href="https://evilcookie.de/linux-file-observability.html">various</a> <a href="https://evilcookie.de/measure-downtime-durations-via-icmp.html">self-made</a> <a href="https://evilcookie.de/how-to-rename-files-without-specifying-the-path-twice.html">featured</a> <a href="https://evilcookie.de/hashsets-in-go.html">images</a>), this was a great opportunity to get more in-depth knowledge.</p>

<ul>
<li>photo grains are not evenly distributed and differ in size, in conclusion digital pixels and analog grains don&rsquo;t have an 1:1 mapping, resolution comparisons are hard</li>
<li>digitalize negatives:

<ul>
<li>scan with a flatbed scanner with <a href="https://de.wikipedia.org/wiki/Durchlichtscanner">&ldquo;Durchlichteinheit&rdquo;</a><sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> or DSLR</li>
<li>import into <a href="https://www.darktable.org/">DarkTable</a></li>
<li>use <a href="https://docs.darktable.org/usermanual/3.8/en/module-reference/processing-modules/negadoctor/">negadoctor</a><sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup></li>
<li>correct exposure</li>
<li>correct size/scale/rotation</li>
</ul></li>
<li>use shadow/sunlight parts of the image for proper white-balancing</li>
</ul>

<p>I&rsquo;ve asked what is the best setup to start with: <em>The best analog camera is the on you can get on ebay.[&hellip;] If you already have a digital camera, stick with the brand to re-use the equipment.[&hellip;]. Start with negative films <a href="https://www.foma.cz/en/catalogue-fomapan-100-classic-detail-406">Fomapan</a> or <a href="https://www.kodak.gtcie.com/de/analogkameras/259-kodak-gold-gb-film-200-135mm-farbfilm-3er-pack-36-posen-0417718808048.html">Kodak Gold</a>.</em></p>

<h2>Wie funktioniert ChatGPT?<a id='chat-gpt'/></h2>

<p>Michael Christen&rsquo;s <a href="https://chemnitzer.linux-tage.de/2024/en/programm/beitrag/186">lecture</a> (<a href="https://media.ccc.de/v/clt24-186-wie-funktioniert-chatgpt-gibt-es-das-auch-als-open-source">video</a>) was a historic journey through 120yrs. of artificial intelligence break-throughs.</p>

<ul>
<li>1906 <a href="https://en.wikipedia.org/wiki/Markov_chain">Markov Chains</a></li>
<li>1948 <a href="https://en.wikipedia.org/wiki/Claude_Shannon">Claude Shanon</a> introduces entropy within information theory and that it isn&rsquo;t evenly distributed over an information</li>
<li>1957 <a href="https://en.wikipedia.org/wiki/Perceptron">Rosenblatt&rsquo;s Perceptron Model</a></li>
<li>1980 <a href="https://en.wikipedia.org/wiki/Chinese_room">Searle&rsquo;s Chinese room</a></li>
<li>1986 <a href="https://en.wikipedia.org/wiki/Backpropagation">Backpropagation</a> and <a href="https://en.wikipedia.org/wiki/Autoencoder">Autoencoder</a></li>
<li>1995 <a href="https://en.wikipedia.org/wiki/Recurrent_neural_network">RNN - Recurren Neural Networks</a> having loops within a network to enable memories (<a href="https://en.wikipedia.org/wiki/Long_short-term_memory">LSTM</a> - Long Short Term Memory)</li>
<li>1998 <a href="https://en.wikipedia.org/wiki/Convolutional_neural_network">CNN - Convolutional Neural Networks</a></li>
<li>2005 <a href="https://en.wikipedia.org/wiki/Latent_space">Embeddings</a> encode natural language into tokens into vectors which can be fed into a network</li>
<li>2014 <a href="https://en.wikipedia.org/wiki/Attention_(machine_learning)">Attention Mechanism</a></li>
<li>2017 <a href="https://en.wikipedia.org/wiki/Transformer_(deep_learning_architecture)">Transformer Architecture</a> <em>Attention is all you need</em></li>
<li>2018 <a href="https://en.wikipedia.org/wiki/GPT-1">GPT-1</a></li>
<li>2022 <a href="https://en.wikipedia.org/wiki/ChatGPT">ChatGPT</a></li>
<li>2023 <a href="https://llama.meta.com/">Llama by Meta</a></li>
<li>2023 <a href="https://github.com/tatsu-lab/stanford_alpaca">Stanford Alpaca</a></li>
</ul>

<p>Learnings:</p>

<ul>
<li>abstraction: reduce the count of nodes within a hidden layer forces the net to learn concepts to overcome this artificial barrier</li>
<li><a href="https://openlm.ai/chatbot-arena/">open_llm_leaderboard</a> is a AI ranking site</li>
<li><a href="https://mistral.ai/news/mixtral-of-experts/">Mixtral 8x7B</a> and <a href="https://oc.app/">OpenChat</a> are better than ChatGPT</li>
<li>models can be mixed by pairwise averaging the weights of two networks</li>
</ul>

<h2>RocketLang - Mein eigener kleiner BER<a id='rocket-lang'/></h2>

<p><a href="https://github.com/Flipez">Robert</a> (former colleague, now at Mozilla) gave <a href="https://chemnitzer.linux-tage.de/2024/en/programm/beitrag/112">a talk</a> (<a href="https://media.ccc.de/v/clt24-112-rocketlang-mein-eigener-kleiner-ber">video</a>) about his implementation of MonkeyLang called <a href="https://rocket-lang.org/">RocketLang</a> based on the book <a href="https://interpreterbook.com/">Writing An Interpreter In Go</a>.</p>

<p>It was an insightful journey through one of those never-ending hobby-projects. It was interesting to see how Robert took language decisions and more interestingly reverted/fixed former decisions. He encouraged people to feel ok in abandoning personal projects for a while, come back later and to <em>make more useless projects</em>. I can totally relate to that. Take this blog for example: I write every now and then, correct old blog posts or correct nothing at all. Who is judging my posts anyway apart from myself? This is fun and it should stay fun :)</p>

<p>Shameless plug: I&rsquo;ve introduced <a href="https://github.com/Flipez/rocket-lang/commits?author=RaphaelPour">itterable integer</a> in RocketLang.</p>

<h2>Der Compiler: Eine Einführung für Anfänger<a id='compiler'/></h2>

<p>This compressed <a href="https://chemnitzer.linux-tage.de/2024/en/programm/beitrag/231">roller coaster ride</a> (<a href="https://media.ccc.de/v/clt24-231-der-compiler-eine-einfuhrung-fur-anfanger">video</a>) through my <a href="https://www2.htw-dresden.de/~beck/Compiler/">compiler module back then at the HTW</a> by Benjamin Stürz reminded me of the good old times :&lsquo;)</p>

<h2>Mini-LLM selbst gemacht<a id='mini-llm'/></h2>

<p>The learning about language models within <a href="https://chemnitzer.linux-tage.de/2024/en/programm/beitrag/287">this lecture</a> (<a href="https://media.ccc.de/v/clt24-287-mini-llm-selbstgemacht">video</a>) was insane.
<a href="https://www.gaertner.de/~neitzel/">Martin Neitzel</a> showed how a minimal <a href="https://en.wikipedia.org/wiki/Large_language_model">LLM (Large Language Model)</a> works using the <a href="https://en.wikipedia.org/wiki/Array_programming">array-language</a> <a href="https://code.jsoftware.com/wiki/Main_Page">J</a> and <a href="https://en.wikipedia.org/wiki/Markov_chain">markov chains</a>. It&rsquo;s basically &ldquo;autocomplete on steroids&rdquo;.</p>

<p>Minimal approach using one follow-up character:</p>

<ol>
<li>define an input text, e.g. <code>Chemnitzer Linuxtage</code></li>
<li>for each unique character, make a list about each follow-up character, e.g. <code>n -&gt; [i,u]</code></li>
<li>end of the input is connected to the beginning, so <code>e -&gt; [m,c]</code></li>
<li>define an input char and grab a random character from its map, e.g. <code>f('n') = random([i,u]) = i</code></li>
</ol>

<p>This works similar to autocomplete but rather than suggesting every follow-up character, it chooses a random one.</p>

<p>Extended approach with <code>n</code> followup characters and <code>m</code> output length:</p>

<ol>
<li>use larger input, e.g. scrape <a href="https://chemnitzer.linux-tage.de/2024/en/">CLT24 website</a></li>
<li>for each unique character, make a list about each <code>n</code> follow up string, e.g. with n=2, <code>e -&gt; [mn, ch]</code></li>
<li>define an input string, append a random followup and repeat until <code>m</code> has been reached</li>
</ol>

<p>Outputs with different parameters:</p>

<ul>
<li><a href="https://media.ccc.de/v/clt24-287-mini-llm-selbstgemacht#t=1200">n=1,m=300</a>: looks gibberish</li>
<li><a href="https://media.ccc.de/v/clt24-287-mini-llm-selbstgemacht#t=1332">n=4,m=300</a>: german words are noticeable</li>
<li><a href="https://media.ccc.de/v/clt24-287-mini-llm-selbstgemacht#t=1417">n=10,m=300</a>: text is clear readable, although meaning and grammar might be off</li>
</ul>

<p>It was very interesting to see how a simple markov-chain can be used to generate readable text. We<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> were so excited about the lecture and the J language, that we registered for the <a href="#j-workshop">J Workshop</a>.</p>

<h2>(Fast) alles was man an der Uni nicht lernt<a id='open-source'/></h2>

<p>The <a href="https://chemnitzer.linux-tage.de/2024/en/programm/beitrag/322">lecture</a> (<a href="https://media.ccc.de/v/clt24-322-fast-alles-was-man-an-der-uni-nicht-lernt">video</a>) from the SUSE Software Engineer <a href="https://dancermak.name/">Dan Čermák</a> was about contributing to- and maintaining open-source projects.
He described his experiences with open-source communities and their dynamics: <em>Technology changes, [but] you always have to work with people.</em></p>

<h2>J Workskop<a id='j-workshop'/></h2>

<ul>
<li><a href="https://dl.acm.org/doi/10.1145/206913.206992">Paper</a></li>
<li><a href="https://www.jsoftware.com">J Homepage</a></li>
<li><a href="https://www.jsoftware.com/help/primer/contents.htm">Primer</a></li>
<li><a href="https://jsoftware.github.io/j-playground/bin/html2/#">Playground</a></li>
<li><a href="https://www.jsoftware.com/help/dictionary/vocabul.htm">Vocabulary</a></li>
</ul>

<p>We<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> had three awesome hours of learning the fundamentals of the array-language J from the inventor <a href="https://de.wikipedia.org/wiki/Kenneth_E._Iverson">Kenneth E. Iversion</a>.</p>

<ul>
<li>everything is an n-dimensional array</li>
<li>primitives over standard library: there are tons of tokens consisting of multiple special chars that have different meaning depending if they&rsquo;re monadic (only left argument) or dyadic (both arguments):

<ul>
<li><code>x &lt;.</code>: round x down</li>
<li><code>x &lt;. y</code>: take minimum of x and y</li>
<li><code>x *</code>: return the sign of x</li>
<li><code>x * y</code>: multiply x and y</li>
</ul></li>
<li>Iverson doesn&rsquo;t want to invent/coin new terms but re-use already existing:

<ul>
<li>token, function: verb</li>
<li>data: noun</li>
</ul></li>
</ul>

<h2>Sticker<a id='sticker'/></h2>

<p><img src="chemnitzer-linuxtage-2024_sticker.jpg"/></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Together with <a href="https://auch.cool/">Flipez</a></li>

<li id="fn:2">Didn&rsquo;t find a proper translation&hellip;</li>

<li id="fn:3">I get the intention for combining negative and doctor, but the name is nevertheless bad. Some alternative suggestions: happyNegative (because happy is a <em>positive</em> emotion and it converts a negative to a positive), NegativeNegative (inverting the inverted makes it uninverted), DrDark, DrNegative&hellip;</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Sun, 24 Mar 2024 19:14:42 +0100</pubDate>
    </item>
    <item>
      <title>ruby - get plain class/instance method list</title>
      <link>https://evilcookie.de/ruby---get-plain-classinstance-method-list.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>ruby - get plain class/instance method list</h1>

<p>tl;dr: <code>&lt;your-class&gt;.methods - Object.methods</code></p>

<p>Whenever I juggle with ruby classes or instances within a ruby REPL<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>, I had hard times to figure out their methods:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="no">Time</span><span class="o">.</span><span class="n">methods</span>
</span></span><span class="line"><span class="cl"><span class="o">=</span><span class="o">&gt;</span> <span class="o">[</span><span class="ss">:at</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:now</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:utc</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:gm</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:local</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:mktime</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:new</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:allocate</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:superclass</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:&lt;=&gt;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:&lt;</span><span class="o">=</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:&gt;=</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:==</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:===</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:included_modules</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:include?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:ancestors</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:attr</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:attr_reader</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:attr_writer</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:attr_accessor</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:freeze</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:inspect</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:public_instance_methods</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:instance_methods</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:const_missing</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:protected_instance_methods</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:private_instance_methods</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:const_set</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:constants</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:remove_class_variable</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:class_variable_get</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:class_variable_set</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:class_variable_defined?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:const_get</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:const_defined?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:&lt;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:&gt;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:public_constant</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:class_variables</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:private_constant</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:deprecate_constant</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:singleton_class?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:const_source_location</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:to_s</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:class_eval</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:include</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:module_exec</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:module_eval</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:prepend</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:undef_method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:alias_method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:class_exec</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:remove_method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:method_defined?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:private_class_method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:public_method_defined?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:private_method_defined?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:protected_method_defined?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:public_class_method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:pretty_print_cycle</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:instance_method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:public_instance_method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:define_method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:autoload</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:autoload?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:pretty_print</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:__binding__</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:pry</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:pretty_print_inspect</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:pretty_print_instance_variables</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:dup</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:itself</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:yield_self</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:then</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:taint</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:tainted?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:untaint</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:untrust</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:untrusted?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:trust</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:frozen?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:methods</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:singleton_methods</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:protected_methods</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:private_methods</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:public_methods</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:instance_variables</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:instance_variable_get</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:instance_variable_set</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:instance_variable_defined?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:remove_instance_variable</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:instance_of?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:kind_of?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:is_a?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:tap</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:display</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:hash</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:singleton_class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:clone</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:public_send</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:public_method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:singleton_method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:define_singleton_method</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:pretty_inspect</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:extend</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:to_enum</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:enum_for</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">:</span><span class="o">=~</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">:</span><span class="o">!~</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:nil?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:eql?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:respond_to?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:object_id</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:send</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:__send__</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">:</span><span class="o">!</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">:</span><span class="o">!=</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:equal?</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:__id__</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:instance_eval</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="ss">:instance_exec</span><span class="o">]</span>
</span></span></code></pre>
<p>I was today years old when I leaned about just subtracting the <code>Object</code> methods (from ruby&rsquo;s holy base object) from <a href="https://stackoverflow.com/a/8595216">SO</a>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">Time</span><span class="o">.</span><span class="n">methods</span> <span class="o">-</span> <span class="no">Object</span><span class="o">.</span><span class="n">methods</span>
</span></span><span class="line"><span class="cl"><span class="o">=</span><span class="o">&gt;</span> <span class="o">[</span><span class="ss">:at</span><span class="p">,</span> <span class="ss">:now</span><span class="p">,</span> <span class="ss">:utc</span><span class="p">,</span> <span class="ss">:gm</span><span class="p">,</span> <span class="ss">:local</span><span class="p">,</span> <span class="ss">:mktime</span><span class="o">]</span>
</span></span></code></pre>
<p>As of writing this post, I just noticed that the relevant class/instance methods are at the beginning of the list, which is kind of handy, too.</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1"><a href="https://github.com/pry/pry">pry</a> ftw.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 18 Mar 2024 06:00:00 +0100</pubDate>
    </item>
    <item>
      <title>git force-push for professionals</title>
      <link>https://evilcookie.de/git-force-push-for-professionals.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>git force-push for professionals</h1>

<p>tl;dr: Use <code>--force-with-lease</code> instead of <code>--force</code> to avoid overwriting upstream changes.</p>

<h2>Introduction</h2>

<p>1st git rule: <strong>don&rsquo;t force-push</strong>. But as an atendee of the <a href="https://docs.github.com/en/get-started/using-git/about-git-rebase">rebase-i-make-my-own-history club</a>, force push is necessary.</p>

<p>But nevertheless overwrites happen, especially when multiple people work on the same branch. This happens mostly for automatic pull-requests like dependency updates.</p>

<p><a href="https://git-scm.com/docs/git-push#Documentation/git-push.txt---no-force-with-lease"><code>--force-with-lease</code></a> got your covered:</p>

<blockquote>
<p>Imagine that you have to rebase what you have already published. You will have to bypass the &ldquo;must fast-forward&rdquo; rule in order to replace the history you originally published with the rebased history. If somebody else built on top of your original history while you are rebasing, the tip of the branch at the remote may advance with their commit, and blindly pushing with &ndash;force will lose their work.</p>
</blockquote>

<h2>Example</h2>

<ol>
<li>make a change upstream</li>
<li>make a change locally</li>
<li>push locally: `git push &ndash;force-with-lease&rsquo;:</li>
</ol>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">To github.com:RaphaelPour/120.git
</span></span><span class="line"><span class="cl"> ! [rejected]        main -&gt; main (stale info)
</span></span><span class="line"><span class="cl"> error: failed to push some refs to &#39;github.com:RaphaelPour/120.git&#39;
</span></span></code></pre>
<p>Otherwise, <code>--force</code> would just steamroll&rsquo; <code>main</code>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">Enumerating objects: 11, done.
</span></span><span class="line"><span class="cl">Counting objects: 100% (11/11), done.
</span></span><span class="line"><span class="cl">Delta compression using up to 16 threads
</span></span><span class="line"><span class="cl">Compressing objects: 100% (11/11), done.
</span></span><span class="line"><span class="cl">Writing objects: 100% (11/11), 4.64 KiB | 2.32 MiB/s, done.
</span></span><span class="line"><span class="cl">Total 11 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0)
</span></span><span class="line"><span class="cl">remote: Resolving deltas: 100% (3/3), done.
</span></span><span class="line"><span class="cl">To github.com:RaphaelPour/120.git
</span></span><span class="line"><span class="cl"> + 2b495e8...ac28eb3 main -&gt; main (forced update)
</span></span></code></pre>]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 11 Mar 2024 12:24:51 +0100</pubDate>
    </item>
    <item>
      <title>Ollama and codellama - enter the AI rabbithole</title>
      <link>https://evilcookie.de/ollama-and-codellama---enter-the-ai-rabbithole.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Ollama and codelama - enter the AI rabbit hole</h1>

<p><a href="https://ollama.com">Ollama</a> makes using models like <a href="https://github.com/facebookresearch/codellama">codellama</a> as easy to use as containers.
I stumpled over it on hacker news and was cruious if it was as easy as claimed.</p>

<h2>Getting started</h2>

<ol>
<li>download and install ollama:

<ul>
<li>Linux: <code>curl -fsSL https://ollama.com/install.sh | sh</code></li>
<li>others: <a href="https://ollama.com/download">Download page</a></li>
</ul></li>
<li>pull e.g. <a href="https://ollama.com/library/codellama">Meta&rsquo;s codellama</a> model: <code>ollama pull codellama</code></li>
<li>run prompt: <code>ollama run codellama</code></li>
</ol>

<ul>
<li><code>set /verbose</code>: see some metrics about each prompt</li>
<li><code>explain following riscv bootloader: &lt;paste&gt;</code> worked pretty well</li>
</ul>

<h2>Prompts</h2>

<p>To improve readability and transparence, prompts are written as citation and answers with italic letters (if not code blocks), like this:</p>

<blockquote>
<p>Prompt</p>
</blockquote>

<p><em>Answer&hellip;</em></p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">code
</span></span></code></pre>
<p><em>More answes</em></p>

<h3>Port scanner</h3>

<blockquote>
<p>Write a go program that checks all well-known tcp ports below 100 if they are open.</p>
</blockquote>

<p><em>Here is an example Go program that checks all TCP ports below 100 on the local machine to see if they are open:</em></p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">package main
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">import (
</span></span><span class="line"><span class="cl">	&#34;fmt&#34;
</span></span><span class="line"><span class="cl">	&#34;net&#34;
</span></span><span class="line"><span class="cl">)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">func main() {
</span></span><span class="line"><span class="cl">	for port := 1; port &lt; 100; port++ {
</span></span><span class="line"><span class="cl">		addr, err := net.ResolveTCPAddr(&#34;tcp&#34;, fmt.Sprintf(&#34;:%d&#34;, port))
</span></span><span class="line"><span class="cl">		if err != nil {
</span></span><span class="line"><span class="cl">			fmt.Println(err)
</span></span><span class="line"><span class="cl">			continue
</span></span><span class="line"><span class="cl">		}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		conn, err := net.DialTCP(&#34;tcp&#34;, nil, addr)
</span></span><span class="line"><span class="cl">		if err == nil {
</span></span><span class="line"><span class="cl">			fmt.Printf(&#34;%d is open\n&#34;, port)
</span></span><span class="line"><span class="cl">			conn.Close()
</span></span><span class="line"><span class="cl">		} else {
</span></span><span class="line"><span class="cl">			fmt.Printf(&#34;%d is closed\n&#34;, port)
</span></span><span class="line"><span class="cl">		}
</span></span><span class="line"><span class="cl">	}
</span></span><span class="line"><span class="cl">}
</span></span></code></pre>
<p><em>This program uses the <code>net</code> package to create a TCP connection on each port in the range [1, 100). If the connection succeeds, the port is considered open and the program prints a message indicating so. If the connection fails or times out, the port is considered closed and the program prints a message indicating so.</em></p>

<p><em>Note that this program will only work if you have permission to create a TCP connection on each port in the range. Additionally, this program will not check for any firewall rules or other network
restrictions that may prevent you from creating a connection on certain ports.</em></p>

<h4>Remarks</h4>

<ul>
<li>compiled without any issue</li>
<li>empty host in <code>ResolveTCPAddr</code> &ldquo;:%d&rdquo; needed to be set to &ldquo;127.0.0.1:%d&rdquo;</li>
<li>dropped else branch to decrease noise</li>
</ul>

<h2>Further reading</h2>

<ul>
<li><a href="https://newsletter.pnote.eu/p/tokyo-context-window-tokenization">Lost in tokenization: Tokyo in context windows</a></li>
<li><a href="https://ai.meta.com/blog/code-llama-large-language-model-coding/">Introducing Code Llama, a state-of-the-art large language model for coding</a></li>
</ul>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 26 Feb 2024 12:16:52 +0100</pubDate>
    </item>
    <item>
      <title>let&#39;s boot with riscv</title>
      <link>https://evilcookie.de/lets-boot-with-riscv.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>let&rsquo;s boot with riscv</h1>

<p>Let&rsquo;s boot some C code<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> with <a href="https://en.wikipedia.org/wiki/RISC-V">riscv64</a> using <a href="https://www.qemu.org/docs/master/system/target-riscv.html">qemu</a>: <a href="https://github.com/RaphaelPour/riscy/tree/main">riscy</a><sup class="footnote-ref" id="fnref:credits"><a href="#fn:credits">2</a></sup></p>

<p>After about <a href="https://evilcookie.de/lets-boot.html">half a year of os development abstinence</a>. I fell into the riscv-os-dev-rabbit-hole. Those risc, arm, riscv buzzwords are in my news bubble for a while. Now it&rsquo;s time to get my hands dirty.</p>

<h4>Contents</h4>

<ul>
<li><a href="#riscv-vs-arm">RISC-V vs. ARM vs. ARM64 vs. AArch64</a></li>
<li><a href="#getting-started">Getting started - barebone tutorial</a>

<ul>
<li><a href="#build">Build</a></li>
</ul></li>
<li><a href="#interact">Interact with the outside world</a>

<ul>
<li><a href="#devices">Devices</a></li>
<li><a href="#drivers">Drivers</a></li>
<li><a href="#magic">Magic address</a></li>
<li><a href="#uart">UART</a></li>
<li><a href="#rtc">RTC</a></li>
</ul></li>
<li><a href="#summary">Summary</a></li>
</ul>

<h2>RISC-V vs. ARM vs. ARM64 vs. AArch64<a id='riscv-vs-arm'/></h2>

<p><a href="https://en.wikipedia.org/wiki/AArch64">ARM64</a> and Aarch64 are both the same<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">3</a></sup>: an implementation of the  proprietary <a href="https://www.ibm.com/history/risc">RISC</a>  architecture family <a href="https://en.wikipedia.org/wiki/ARM_architecture_family">ARM</a>. <a href="https://en.wikipedia.org/wiki/RISC-V">RISC-V</a> on the other side is an open-source architecture.</p>

<p>Those RISC&rsquo;s are fairly modern<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">4</a></sup> and faster than CISC due to <a href="https://cs.stanford.edu/people/eroberts/courses/soco/projects/risc/risccisc/">their nature</a> of being <em>reduced</em> instead of <em>complex</em>. I&rsquo;m not sure what this &ldquo;faster&rdquo; actually means while a CISC operation may be slower than a single RISC operation, but with RISC more operations are needed.</p>

<h2>Getting started - barebone tutorial<a id="getting-started"/></h2>

<p>I initialized my <a href="https://github.com/RaphaelPour/riscy">riscy</a> bootloader using the <a href="https://wiki.osdev.org/RISC-V_Bare_Bones">os.dev risc-v bare bones</a> tutorial containing everything needed for a hello world:</p>

<ul>
<li><a href="https://wiki.osdev.org/RISC-V_Bare_Bones#entry.S"><code>entry.S</code></a>: Entry point and initial bootloader preparing everything before calling the main function in the C kernel code.</li>
<li><a href="https://wiki.osdev.org/RISC-V_Bare_Bones#kernel.c"><code>kernel.c</code></a>: C kernel printing hello world and reading from the keyboard by <a href="https://docs.arduino.cc/learn/communication/uart/">UART</a>.</li>
<li><a href="https://wiki.osdev.org/RISC-V_Bare_Bones#linker.ld"><code>linker.ld</code></a>: Defines the <a href="https://evilcookie.de/lets-boot.html#memory-layout">memory layout</a> of the resulting binary image that can be booted by qemu.</li>
</ul>

<h3>Build<a id="build"/></h3>

<p>In order to compile and link riscv code on a x86 machine, a cross-compiler version of gcc is needed. For Ubuntu and Fedora I could make out the package <code>gcc-riscv64-linux-gnu</code> containing all needed binaries.</p>

<p>Despite the different binaries names and the dropped <code>-lgcc</code> flag<sup class="footnote-ref" id="fnref:4"><a href="#fn:4">5</a></sup>, the commands look the same as in the Tutorial:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ riscv64-linux-gnu-gcc -Wall -Wextra -c -mcmodel<span class="o">=</span>medany kernel.c -o kernel.o -ffreestanding
</span></span><span class="line"><span class="cl">$ riscv64-linux-gnu-gcc -c entry.S -o entry.o
</span></span><span class="line"><span class="cl">$ riscv64-linux-gnu-ld -T linker.ld -nostdlib kernel.o entry.o -o kernel.elf
</span></span></code></pre>
<p>Let&rsquo;s boot it via <code>qemu-system-riscv64 -machine virt -bios none -kernel kernel.elf -serial mon:stdio</code>.</p>

<p><img src="lets-boot-with-riscv_first_boot.png"/></p>

<p>\o/</p>

<h2>Interact with the outside world<a id="interact"/></h2>

<p>Devices and their drivers are needed to interact with the outside world. Usually devices are defined by the underlying hardware. In our case Qemu and the used machine type <code>virt</code> defines what devices can be used. A driver is defined by the operating system and provides an abstraction of such devices. The Tutorial makes use of the UART device for providing a simple console. Let&rsquo;s discover devices and drivers separately.</p>

<h3>Devices<a id="devices"/></h3>

<p>Qemu provides <a href="https://www.qemu.org/docs/master/system/riscv/virt.html">a list of supported devices</a> for our machine type <code>virt</code>. We also can make out our UART device.</p>

<p>But how can we make use of them?</p>

<h3>Drivers<a id="drivers"/></h3>

<p>Looking at the <a href="https://wiki.osdev.org/RISC-V_Bare_Bones">Tutorial</a>, the driver consists of a magic address and&hellip; well actually nothing more than read and write from it:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">uart</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x10000000</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">putchar</span><span class="p">(</span><span class="kt">char</span> <span class="n">c</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="o">*</span><span class="n">uart</span> <span class="o">=</span> <span class="n">c</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">putchar</span><span class="p">(</span><span class="o">*</span><span class="n">uart</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>How can this make any sense?</p>

<h4>Magic address<a id="magic"/></h4>

<p>The address is actually well-defined by Qemu&rsquo;s machine type for the UART device. As far as I understood it, the address-space of the devices are mapped into our address space and directly usable. Qemu can dump all those devices and addresses which can be made readable using the device-tree-compiler, as I found out via <a href="https://twilco.github.io/riscv-from-scratch/2019/07/08/riscv-from-scratch-3.html#hardware-layout-in-review">this riscv-from-scratch blog post</a>.</p>

<p>And again, we can can make out our UART device with some additional information:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">chosen {
</span></span><span class="line"><span class="cl">  bootargs = [00];
</span></span><span class="line"><span class="cl">  stdout-path = &#34;/soc/uart@10000000&#34;;
</span></span><span class="line"><span class="cl">};
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">uart@10000000 {
</span></span><span class="line"><span class="cl">  interrupts = &lt;0x0a&gt;;
</span></span><span class="line"><span class="cl">  interrupt-parent = &lt;0x03&gt;;
</span></span><span class="line"><span class="cl">  clock-frequency = &#34;\08@&#34;;
</span></span><span class="line"><span class="cl">  reg = &lt;0x00 0x10000000 0x00 0x100&gt;;
</span></span><span class="line"><span class="cl">  compatible = &#34;ns16550a&#34;;
</span></span><span class="line"><span class="cl">};
</span></span></code></pre>
<ul>
<li>uart device emulates the  <a href="https://en.wikipedia.org/wiki/16550_UART#A">ns16550A</a> IC</li>
<li>address spaces starts at <em>magic address</em> <code>0x10000000</code></li>
<li>qemu uses this device for serial stdin/stdout</li>
</ul>

<h3>UART<a id="uart"/></h3>

<p>The <a href="https://docs.arduino.cc/learn/communication/uart/">Universal Asynchronous Receiver-Transmitter</a> is used for serial console. Looking at the tutorial, they seem to just read/write to a pointer:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="c1">// UART address
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">uart</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x10000000</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// print char
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="o">*</span><span class="n">uart</span> <span class="o">=</span> <span class="n">c</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// read char
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">putchar</span><span class="p">(</span><span class="o">*</span><span class="n">uart</span><span class="p">)</span><span class="p">;</span>
</span></span></code></pre>
<p>Coming from traditional application development, this look very odd assigning a value to a variable that was read from the same variable before.
It makes sense because the <code>uart</code> variable is not pointing to ordinary memory but the address space of the UART device, starting with our magic address.
The device actualy reacts to bytes we write and itself writes something back.</p>

<p>Currently our keyboard is connected (via qemu) to read buffer of the device and the stdout of our terminal (again via qemu) is connected to the write buffer.</p>

<p>Since this barely works with stdin and it isn&rsquo;t clear how the driver is set up, I rather set it up explicitly. There is a pretty short but descriptive <a href="https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/uart.c">riscv uart driver</a> to gain inspiration.</p>

<p>First all needed addresses and flags get defined in <a href="https://github.com/RaphaelPour/riscy/blob/main/driver/uart.h">the header</a>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">define UART0 0x10000000</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">define uart_addr(offset) ((unsigned char *)(UART0 + offset))</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">define uart_write(offset, value) (*(uart_addr(offset)) = (value))</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">define uart_read(offset) (*(uart_addr(offset)))</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cm">/* The Interrupt Enable Register (IER) masks the incoming interrupts from receiver ready,
</span></span></span><span class="line"><span class="cl"><span class="cm"> * transmitter empty, line status and modem status registers to the INT output pin.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">define INTERRUPT_ENABLE_REGISTER 0x1</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">define INTERRUPT_ENABLE_REGISTER_RX_ENABLE 0x1</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">define INTERRUPT_ENABLE_REGISTER_TX_ENABLE 0x2</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cm">/* The line Control Register is used to specify the asynchronous data communication format. 
</span></span></span><span class="line"><span class="cl"><span class="cm"> * The number of the word length, stop bits, and parity can be selected by writing appro-
</span></span></span><span class="line"><span class="cl"><span class="cm"> * priate bits in this register.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">define LINE_CONTROL_REGISTER 0x3</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cm">/* The internal baud rate counter latch enable (DLAB).*/</span>
</span></span><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">define LINE_CONTROL_REGISTER_BAUD_LATCH (0x1&lt;&lt;7)</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cm">/* bit 0+1: word length = 0b11 =&gt; 8 bits
</span></span></span><span class="line"><span class="cl"><span class="cm"> * bit 2:   number of stop bits = 0 =&gt; 1 bit
</span></span></span><span class="line"><span class="cl"><span class="cm"> * bit 3:   parity = 0 =&gt; no parity
</span></span></span><span class="line"><span class="cl"><span class="cm"> * bit 4:   even/odd parity =&gt; doesn&#39;t matter since parity is off
</span></span></span><span class="line"><span class="cl"><span class="cm"> * bit 5:   force parity =&gt; -*-
</span></span></span><span class="line"><span class="cl"><span class="cm"> * bit 6:   break control = 0 =&gt; no break control
</span></span></span><span class="line"><span class="cl"><span class="cm"> * bit 7:   set baud rate = 0 =&gt; don&#39;t set baud rate
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">define LINE_CONTROL_REGISTER_EIGHT_BITS_NO_PARITY 0x3</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cm">/* This register is used to enable the FIFOs, clear the FIFOs, set the receiver FIFO trigger 
</span></span></span><span class="line"><span class="cl"><span class="cm"> * level, and select the type of DMA signaling.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">define FIFO_CONTROL_REGISTER 0x2</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">define FIFO_CONTROL_REGISTER_ENABLE 0x1</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">define FIFO_CONTROL_REGISTER_CLEAR_RX 0x2</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">define FIFO_CONTROL_REGISTER_CLEAR_TX 0x4</span><span class="cp">
</span></span></span></code></pre>
<p>Then use them within <a href="https://github.com/RaphaelPour/riscy/blob/main/driver/uart.h">the module&rsquo;s</a> initializer:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">uart_init</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// disable any interrupt, so we can set up some uart settings
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="n">uart_write</span><span class="p">(</span><span class="n">INTERRUPT_ENABLE_REGISTER</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">)</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// enter baud rate mode
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="n">uart_write</span><span class="p">(</span><span class="n">LINE_CONTROL_REGISTER</span><span class="p">,</span> <span class="n">LINE_CONTROL_REGISTER_BAUD_LATCH</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// set baud rate to 38.4K
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="n">uart_write</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">uart_write</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// leave baud rate mode
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="n">uart_write</span><span class="p">(</span><span class="n">LINE_CONTROL_REGISTER</span><span class="p">,</span> <span class="n">LINE_CONTROL_REGISTER_EIGHT_BITS_NO_PARITY</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// enable and clear FIFO
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="n">uart_write</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">FIFO_CONTROL_REGISTER</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">    <span class="n">FIFO_CONTROL_REGISTER_ENABLE</span> <span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">FIFO_CONTROL_REGISTER_CLEAR_TX</span> <span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">FIFO_CONTROL_REGISTER_CLEAR_RX</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// enable interrupts again
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="n">uart_write</span><span class="p">(</span><span class="n">INTERRUPT_ENABLE_REGISTER</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">INTERRUPT_ENABLE_REGISTER_RX_ENABLE</span> <span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">INTERRUPT_ENABLE_REGISTER_TX_ENABLE</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p><img src="lets-boot-with-riscv_uart_works.gif"/></p>

<h3>RTC<a id="rtc"/></h3>

<p>After uart is working good enough, I wondered which other devices Qemu&rsquo;s virt machinetype offers. Right in the beginning of the
device-tree-map, a goldfish got my attention:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">rtc@101000 {
</span></span><span class="line"><span class="cl">  interrupts = &lt;0x0b&gt;;
</span></span><span class="line"><span class="cl">  interrupt-parent = &lt;0x03&gt;;
</span></span><span class="line"><span class="cl">  reg = &lt;0x00 0x101000 0x00 0x1000&gt;;
</span></span><span class="line"><span class="cl">  compatible = &#34;google,goldfish-rtc&#34;;
</span></span><span class="line"><span class="cl">};
</span></span></code></pre>
<p>This is the google goldfish rtc device mapped at <code>0x101000</code>. Qemu has a documentation about the <a href="https://android.googlesource.com/platform/external/qemu/+/master/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT#203">rtc device</a> and the linux kernel has a <a href="https://github.com/torvalds/linux/blob/master/drivers/rtc/rtc-goldfish.c#L110">pretty small implementation</a>.</p>

<p>I came up with something like this:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kt">uint64_t</span> <span class="nf">time</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">volatile</span> <span class="kt">uint32_t</span> <span class="o">*</span><span class="n">rtc</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint32_t</span> <span class="o">*</span><span class="p">)</span> <span class="mh">0x101000</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">uint64_t</span> <span class="n">time_low</span> <span class="o">=</span> <span class="n">rtc</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">uint64_t</span> <span class="n">time_high</span> <span class="o">=</span> <span class="n">rtc</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span><span class="n">time_high</span> <span class="o">&lt;</span><span class="o">&lt;</span> <span class="mi">32</span> <span class="o">|</span> <span class="n">time_low</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Which lead to the first ever nanosecond unix timestamp printed to the riscy console: <code>1707410202187052000</code><sup class="footnote-ref" id="fnref:5"><a href="#fn:5">6</a></sup>.</p>

<h2>Inline assembler<a id="inline-assembler"/></h2>

<p>After having some convenience with basic drivers and an essential standard lib, it&rsquo;s time to checkout riscv assembler itself using inline assembler.</p>

<p>Incrementing a number should be a simple start, right? Well, unlike x86&rsquo;s <code>inc</code>, there is no pedant here. But <code>addi</code> gotcha covered: <code>addi result, a, number</code>  where <code>result</code> and <code>a</code> are variables and <code>number</code> is a so-called <em>imediate</em> (literal) value. The inline syntax is a bit odd since it breaks the usual format we know from C/printf. <a href="https://stackoverflow.com/q/72640997">This SO Post</a> helped me to find the right syntax.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">inc</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">volatile</span> <span class="kt">int</span> <span class="n">result</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">asm</span> <span class="k">volatile</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="sa"></span><span class="s">&#34;</span><span class="s">addi %0, %1, 1;</span><span class="s">&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="o">:</span> <span class="sa"></span><span class="s">&#34;</span><span class="s">=r</span><span class="s">&#34;</span> <span class="p">(</span><span class="n">result</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="o">:</span> <span class="sa"></span><span class="s">&#34;</span><span class="s">r</span><span class="s">&#34;</span> <span class="p">(</span><span class="n">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>The keyword <code>volatile</code> is recommended to prevent compiler optimizations.</p>

<h2>Summary<a id="summary"/></h2>

<p>Although I learned a bit about RISC and the hardware qemu provides for it, I barely touched the differences between x86 and RISC. I wouldn&rsquo;t wonder
if the C &ldquo;core&rdquo; lib (despite the machine type specialities) is architecture-agnostic. But I really enjoyed starting with nothing and introduce concepts
like strings or time. The bootloader is still a bit mysterious for me and I couldn&rsquo;t figure out how to support VGA, but the UART driver was pretty straight forward.</p>

<p>Developing my first driver from scratch with my own findings, going through kernel code and tinkering around was awesome. It&rsquo;s just a small goldfish but it meant a lot.</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Assembler won&rsquo;t matter much as I use the bootloader from the bare-bones tutorial and start development with C for convenience.</li>

<li id="fn:credits">Together with <a href="https://github.com/Tch1b0/">Tch1b0</a></li>

<li id="fn:2">Based on <a href="https://stackoverflow.com/a/47274698">SO</a>: Apple named it <code>arm64</code> and all the others <code>aarch64</code>.</li>

<li id="fn:3">RISC-V is from <a href="https://en.wikipedia.org/wiki/RISC-V">2014</a> and not unlike the famous x86/i386 from <a href="https://en.wikipedia.org/wiki/X86">1978</a>.</li>

<li id="fn:4"><code>riscv64-linux-gnu-ld: cannot find -lgcc: no error</code> ¯\<em>(ツ)</em>/¯</li>

<li id="fn:5"><code>$ date -d @1707410202.187052000 +&quot;%Y-%m-%d %H:%M:%S.%N&quot;</code>: 2024-02-08 17:36:42.187052000</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 20 Feb 2024 17:38:16 +0100</pubDate>
    </item>
    <item>
      <title>execute c source files</title>
      <link>https://evilcookie.de/execute-c-source-files.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>execute c source files</h1>

<p><em>tl;dr</em>:</p>

<ol>
<li>add <code>//usr/bin/gcc &quot;$0&quot; &amp;&amp; exec ./a.out &quot;$@&quot;</code> to the first line of your <code>example.c</code></li>
<li>make executable: <code>chmod +x example.c</code></li>
<li>run it: <code>./example.c</code></li>
</ol>

<p>I have got a folder called <code>lab</code> for those quick &lsquo;n&rsquo; dirty programs to test some language features or other interesting behavior. While <code>golang</code> programs can be easily executed via <a href="https://pkg.go.dev/cmd/go#hdr-Compile_and_run_Go_program"><code>go run &lt;go file&gt;</code></a> and this is not the case for c programs needing a built step. There is AFAIK no such command like <code>gcc run</code>.</p>

<p><img src="execute-c-source-files_lab.png"/></p>

<h2>Shebang</h2>

<p>Linux&rsquo;s <a href="https://linux.die.net/man/2/execve"><code>execve(2)</code></a> syscall supports <a href="https://en.wikipedia.org/wiki/Shebang_%28Unix%29">shebangs</a>. When the first line starts with <code>#!</code> aka shebang, it will get parsed by the kernels <a href="https://github.com/torvalds/linux/blob/3e732ebf7316ac83e8562db7e64cc68aec390a18/fs/binfmt_script.c#L34">binfmt_script</a> module and used for executing the rest of the file. This enables to run various non-binary scripts (bash, python, ruby, <your-fancy-new-language>)  like <code>./program</code> without using the interpreter.</p>

<p>Can we use a shebang for c source files? tl;dr: nope, as far as I tried this is not possible.</p>

<p>I&rsquo;ve ended up with something like:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cp">#!/usr/bin/tail -n+2 main.c /tmp/main.c &amp;&amp; /usr/bin/gcc /tmp/main.c -o main &amp;&amp; ./main #
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="c1">#include &lt;stdio.h&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#include &lt;stdlib.h&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">int main<span class="o">(</span>int argc, char *argv<span class="o">[</span><span class="o">]</span><span class="o">)</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span><span class="o">(</span>int <span class="nv">i</span> <span class="o">=</span> 0<span class="p">;</span>i&lt;argc<span class="p">;</span> i++<span class="o">)</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    printf<span class="o">(</span><span class="s2">&#34;%d: %s\n&#34;</span>, i, argv<span class="o">[</span>i<span class="o">]</span><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="o">}</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">/*
</span></span><span class="line"><span class="cl"> * $ ./main.c <span class="m">1</span> <span class="m">2</span> <span class="m">3</span>
</span></span><span class="line"><span class="cl"> * /usr/bin/tail: invalid number of lines: ‘+2 main.c /tmp/main.c <span class="o">&amp;&amp;</span> /usr/bin/gcc /tmp/main.c -o main <span class="o">&amp;&amp;</span> ./main <span class="c1">#’</span>
</span></span><span class="line"><span class="cl"> */
</span></span></code></pre>
<p>This doesn&rsquo;t work while everything after <code>tail</code> gets <a href="https://github.com/torvalds/linux/blob/3e732ebf7316ac83e8562db7e64cc68aec390a18/fs/binfmt_script.c#L81">interpreted as one argument</a>.</p>

<h2>binfmt fallback</h2>

<p>Just before I was about to give up, I&rsquo;ve found an <a href="https://stackoverflow.com/a/29709521">SO post</a> suggesting:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">//usr/bin/clang <span class="s2">&#34;</span><span class="nv">$0</span><span class="s2">&#34;</span> <span class="o">&amp;&amp;</span> <span class="nb">exec</span> ./a.out <span class="s2">&#34;</span><span class="nv">$@</span><span class="s2">&#34;</span>
</span></span></code></pre>
<p>I&rsquo;ve adapted it to my use-case and voila:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="c1">//usr/bin/gcc &#34;$0&#34; &amp;&amp; ./a.out &#34;$@&#34;;exit
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[</span><span class="p">]</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;</span><span class="n">argc</span><span class="p">;</span> <span class="n">i</span><span class="o">+</span><span class="o">+</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">%d: %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cm">/* 
</span></span></span><span class="line"><span class="cl"><span class="cm"> * $ ./main.c 1 2 3
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 0: ./a.out
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 1: 1
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 2: 2
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 3: 3
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span></code></pre>
<ul>
<li><code>//</code>: c single-line comment to avoid gcc to interpret this line</li>
<li><code>//usr/bin/gcc &quot;$0&quot;</code>: compile file itself  using the absolute path to the compiler, multiple slashes will automatically compacted to one, so // is no problem</li>
<li><code>exec ./.aout &quot;$@&quot;</code>: execute the built binary (named <code>a.out</code> per default) with all arguments which were initially added to the program call <code>./program arg1 arg2...</code>, exec replaces the current process which is important as the rest of the c source file otherwise gets interpreted</li>
</ul>

<p>Well, I guess this works because after <code>binfmt</code> fails to detect any elf-binary or shebang, bash executes it in the current context, which is actually bash.</p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 30 Jan 2024 16:28:16 +0100</pubDate>
    </item>
    <item>
      <title>go integration tests with ginkgo and gomega</title>
      <link>https://evilcookie.de/go-integration-tests-with-ginkgo-and-gomega.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>go integration tests with ginkgo and gomega</h1>

<p><img src="go-integration-tests-with-ginkgo-and-gomega_bdd.png"/>
<small style="color:gray">Headlights of Louvre&rsquo;s statuary hall in Paris.</small></p>

<p>Today, I&rsquo;ve checked out the BDD<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> testing framework <a href="https://pkg.go.dev/github.com/onsi/ginkgo/v2">ginkgo</a> with the matcher library <a href="https://pkg.go.dev/github.com/onsi/gomega">gomega</a> for integration tests with go. The motivation was to find an alternative for my go-to testing framework <a href="https://rspec.info/documentation/3.9/rspec-expectations/">rspec</a>. Although in ruby, I anyway used it for go projects like <a href="https://github.com/RaphaelPour/blogctl/blob/main/spec.rb">blogctl</a>.</p>

<ul>
<li><a href="#rspec">rspec - Were I came from</a></li>
<li><a href="#integration-test-frameworks">Integration test frameworks in go</a></li>
<li><a href="#ginkgo">ginkgo</a>

<ul>
<li><a href="#setup">Setup</a></li>
<li><a href="#show-version">Show version</a></li>
<li><a href="#real-tests">Real tests</a></li>
</ul></li>
<li><a href="#thoughts">Thoughts</a></li>
</ul>

<h2>rspec - Where I came from<a id='rspec'/></h2>

<p>The rspec <a href="https://martinfowler.com/dsl.html">DSL</a> together with ruby itself makes it easy to write down tests pretty quickly. At least for me its quicker than doing the same in go (until now?):</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;rspec&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;open3&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">describe</span> <span class="s1">&#39;CLI&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">context</span> <span class="s1">&#39;Trivial test cases&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">it</span> <span class="s1">&#39;shows a version&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="n">out</span><span class="p">,</span> <span class="n">err</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="no">Open3</span><span class="o">.</span><span class="n">capture3</span><span class="p">(</span><span class="s2">&#34;</span><span class="s2">blogctl --version</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">expect</span><span class="p">(</span><span class="n">err</span><span class="p">)</span><span class="o">.</span><span class="n">to</span> <span class="n">eq</span> <span class="s2">&#34;</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="n">expect</span><span class="p">(</span><span class="n">out</span><span class="p">)</span><span class="o">.</span><span class="n">to</span> <span class="n">match</span><span class="p">(</span><span class="sr">/</span><span class="sr">BuildVersion:</span><span class="sr">/</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">expect</span><span class="p">(</span><span class="n">out</span><span class="p">)</span><span class="o">.</span><span class="n">to</span> <span class="n">match</span><span class="p">(</span><span class="sr">/</span><span class="sr">BuildDate:</span><span class="sr">/</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span></code></pre>
<h2>Integration test frameworks in go<a id="integration-test-frameworks"/></h2>

<p>There are a bunch of testing frameworks on the  <a href="https://github.com/avelino/awesome-go#testing">awesome-go list</a> that look interesting for BDD integration testing.</p>

<table>
<thead>
<tr>
<th>Project</th>
<th>Active development</th>
<th>Specify tests within go</th>
<th>Various nestable containers</th>
<th><code>(Before|After)(All|Each)</code> scripts</th>
</tr>
</thead>

<tbody>
<tr>
<td><a href="https://github.com/fulldump/biff">fulldump/biff</a></td>
<td>y</td>
<td>n</td>
<td>?</td>
<td>?</td>
</tr>

<tr>
<td><a href="https://github.com/hedhyw/gherkingen">hedhyw/gherkingen</a></td>
<td>y</td>
<td>n</td>
<td>?</td>
<td>?</td>
</tr>

<tr>
<td><a href="https://github.com/onsi/ginkgo">ginkgo</a></td>
<td>y</td>
<td>y</td>
<td>y</td>
<td>y</td>
</tr>

<tr>
<td><a href="https://github.com/smartystreets/goconvey/">smartystreets/goconvey/</a></td>
<td>y</td>
<td>y</td>
<td>n</td>
<td>?</td>
</tr>

<tr>
<td><a href="https://github.com/cucumber/godog">cucumber/godog</a></td>
<td>y</td>
<td>n</td>
<td>y</td>
<td>?</td>
</tr>

<tr>
<td><a href="https://github.com/corbym/gogiven">corbym/gogiven</a></td>
<td>y</td>
<td>n</td>
<td>?</td>
<td>?</td>
</tr>

<tr>
<td><a href="https://github.com/luontola/gospec">luontola/gospec</a></td>
<td>n</td>
<td>y</td>
<td>?</td>
<td>?</td>
</tr>

<tr>
<td><a href="https://github.com/stesla/gospecify">stesla/gospecify</a></td>
<td>n</td>
<td>?</td>
<td>?</td>
<td>?</td>
</tr>

<tr>
<td><a href="https://github.com/pavlo/gosuite">pavlo/gosuite</a></td>
<td>n</td>
<td>y</td>
<td>n</td>
<td>y</td>
</tr>
</tbody>
</table>

<ul>
<li>Active development: last contribution was within the last year</li>
<li>Specify tests within go:  The test can be specified within go.</li>
<li>Various nestable containers: Analog to rspecs <code>decribe</code> and  <code>context</code> container that can be nested.</li>
<li><code>(Before|After)(All|Each)</code> scripts: rspec alike setup and tear down functions for all and test-wise</li>
<li><code>?</code>: I skipped evaluating this feature as it wasn&rsquo;t obvious from the readme and another feature was unsupported anyway.</li>
</ul>

<h2>ginkgo<a id="ginkgo"/></h2>

<p><a href="https://pkg.go.dev/github.com/onsi/ginkgo/v2">Ginkgo</a> offers a similar Given-When-Then approach after <a href="https://github.com/onsi/ginkgo#ginkgo">looking at the example in the readme</a>. <a href="https://pkg.go.dev/github.com/onsi/gomega">Gomega</a> is the matcher library, used by ginkgo. They&rsquo;re both from the same author.</p>

<p>I&rsquo;ve used my renaming tool <a href="https://evilcookie.de/how-to-rename-files-without-specifying-the-path-twice.html">r</a> to check it out.</p>

<h3>Setup<a id="setup"/></h3>

<ol>
<li>get ginkgo cli: <code>go install github.com/onsi/ginkgo/v2/ginkgo@latest</code></li>
<li>add gomega dependency to your go-mod-managed project: <code>go get github.com/onsi/gomega@latest</code></li>
<li>initialize ginkgo which creates a testing entrypoint aka test suite: <code>ginkgo bootstrap</code></li>
<li>generate spec for main: <code>ginkgo generate</code></li>
<li>run tests: <code>ginkgo</code></li>
</ol>

<p>This should&rsquo;ve created two files:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="c1">// test suite
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="c1">// r_suite_test.go
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kn">package</span> <span class="nx">r_test</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span> <span class="s">&#34;github.com/onsi/ginkgo/v2&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span> <span class="s">&#34;github.com/onsi/gomega&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;testing&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">TestBooks</span><span class="p">(</span><span class="nx">t</span> <span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">T</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">RegisterFailHandler</span><span class="p">(</span><span class="nx">Fail</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">RunSpecs</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="s">&#34;R Suite&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre><pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="c1">// spec
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="c1">// r_test.go
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kn">package</span> <span class="nx">r_test</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span> <span class="s">&#34;github.com/onsi/ginkgo/v2&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span> <span class="s">&#34;github.com/onsi/gomega&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">_</span> <span class="p">=</span> <span class="nf">Describe</span><span class="p">(</span><span class="s">&#34;R&#34;</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="p">)</span>
</span></span></code></pre>
<h3>Show version<a id="show-version"/></h3>

<p>At first I&rsquo;ve  adapted the version test from the previous rspec example:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main_test</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;os&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;os/exec&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;path/filepath&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="s">&#34;github.com/bsm/gomega/gbytes&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;github.com/bsm/gomega/gexec&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span> <span class="s">&#34;github.com/onsi/ginkgo/v2&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span> <span class="s">&#34;github.com/onsi/gomega&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">_</span> <span class="p">=</span> <span class="nf">Describe</span><span class="p">(</span><span class="s">&#34;R&#34;</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nf">When</span><span class="p">(</span><span class="s">&#34;binary is used correctly&#34;</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nf">It</span><span class="p">(</span><span class="s">&#34;shows version&#34;</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">session</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">gexec</span><span class="p">.</span><span class="nf">Start</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">				<span class="nx">exec</span><span class="p">.</span><span class="nf">Command</span><span class="p">(</span><span class="s">&#34;ci-build/r&#34;</span><span class="p">,</span> <span class="s">&#34;--version&#34;</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="nx">GinkgoWriter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="nx">GinkgoWriter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="p">.</span><span class="nf">ShouldNot</span><span class="p">(</span><span class="nf">HaveOccurred</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Eventually</span><span class="p">(</span><span class="nx">session</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nx">gexec</span><span class="p">.</span><span class="nf">Exit</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">session</span><span class="p">.</span><span class="nx">Out</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nx">gbytes</span><span class="p">.</span><span class="nf">Say</span><span class="p">(</span><span class="s">`</span><span class="s">(?m)BuildVersion:.*\nBuildDate:</span><span class="s">`</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">session</span><span class="p">.</span><span class="nx">Err</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nx">gbytes</span><span class="p">.</span><span class="nf">Say</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="p">)</span>
</span></span></code></pre>
<ul>
<li>provides <a href="https://onsi.github.io/ginkgo/#organizing-specs-with-container-nodes">containers</a> like <code>Describe</code>, <code>When</code> and <code>It</code> similar to rspecs <code>describe</code>, <code>context</code> and <code>it</code></li>
<li>few more lines, words and brackets, as expected in go</li>
<li>gomega provides so-called <a href="https://onsi.github.io/gomega/#making-asynchronous-assertions">Asynchronous Assertions</a> like <code>Eventually</code> which checks the expection periodically for some time, which is very handy</li>
<li>helper libs like <code>gexec</code> and <code>gbytes</code> simplify the matcher that would otherwise be a bit more fiddly in go</li>
<li><code>gbytes</code> directly awaits the saying to be a regex, like a charm!</li>
</ul>

<h3>Real tests<a id="real-tests"/></h3>

<p>The following tests use before and after scripts that set up the temporary environment for some real<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> tests:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main_test</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;os&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;os/exec&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;path/filepath&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="s">&#34;github.com/bsm/gomega/gbytes&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;github.com/bsm/gomega/gexec&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span> <span class="s">&#34;github.com/onsi/ginkgo/v2&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span> <span class="s">&#34;github.com/onsi/gomega&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">_</span> <span class="p">=</span> <span class="nf">Describe</span><span class="p">(</span><span class="s">&#34;R&#34;</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nf">When</span><span class="p">(</span><span class="s">&#34;binary is used correctly&#34;</span><span class="p">,</span> <span class="nx">Ordered</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="kd">var</span> <span class="nx">tempFile</span> <span class="o">*</span><span class="nx">os</span><span class="p">.</span><span class="nx">File</span>
</span></span><span class="line"><span class="cl">		<span class="kd">var</span> <span class="nx">tempDir</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="nf">BeforeAll</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="kd">var</span> <span class="nx">err</span> <span class="kt">error</span>
</span></span><span class="line"><span class="cl">			<span class="nx">tempDir</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nx">os</span><span class="p">.</span><span class="nf">MkdirTemp</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nf">TempDir</span><span class="p">(</span><span class="p">)</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nf">BeNil</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="nf">AfterAll</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">os</span><span class="p">.</span><span class="nf">RemoveAll</span><span class="p">(</span><span class="nx">tempDir</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="nf">BeforeEach</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">ctx</span> <span class="nx">SpecContext</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="kd">var</span> <span class="nx">err</span> <span class="kt">error</span>
</span></span><span class="line"><span class="cl">			<span class="nx">tempFile</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nx">os</span><span class="p">.</span><span class="nf">CreateTemp</span><span class="p">(</span><span class="nx">tempDir</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="p">.</span><span class="nf">ShouldNot</span><span class="p">(</span><span class="nf">HaveOccurred</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="nf">It</span><span class="p">(</span><span class="s">&#34;renames file&#34;</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">renamed</span> <span class="o">:=</span> <span class="nx">filepath</span><span class="p">.</span><span class="nf">Base</span><span class="p">(</span><span class="nx">tempFile</span><span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="p">)</span><span class="p">)</span> <span class="o">+</span> <span class="s">&#34;2&#34;</span>
</span></span><span class="line"><span class="cl">			<span class="nx">session</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">gexec</span><span class="p">.</span><span class="nf">Start</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">				<span class="nx">exec</span><span class="p">.</span><span class="nf">Command</span><span class="p">(</span><span class="s">&#34;ci-build/r&#34;</span><span class="p">,</span> <span class="nx">tempFile</span><span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="p">)</span><span class="p">,</span> <span class="nx">renamed</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="nx">GinkgoWriter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="nx">GinkgoWriter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="p">.</span><span class="nf">ShouldNot</span><span class="p">(</span><span class="nf">HaveOccurred</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Eventually</span><span class="p">(</span><span class="nx">session</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nx">gexec</span><span class="p">.</span><span class="nf">Exit</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="nx">_</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nx">os</span><span class="p">.</span><span class="nf">Stat</span><span class="p">(</span><span class="nx">tempFile</span><span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="p">.</span><span class="nf">To</span><span class="p">(</span><span class="nf">MatchError</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">IsNotExist</span><span class="p">,</span> <span class="s">&#34;It is not existing&#34;</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="nx">_</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nx">os</span><span class="p">.</span><span class="nf">Stat</span><span class="p">(</span><span class="nx">filepath</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">tempDir</span><span class="p">,</span> <span class="nx">renamed</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nf">BeNil</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="nf">It</span><span class="p">(</span><span class="s">&#34;shows version&#34;</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">session</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">gexec</span><span class="p">.</span><span class="nf">Start</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">				<span class="nx">exec</span><span class="p">.</span><span class="nf">Command</span><span class="p">(</span><span class="s">&#34;ci-build/r&#34;</span><span class="p">,</span> <span class="s">&#34;--version&#34;</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="nx">GinkgoWriter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="nx">GinkgoWriter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="p">.</span><span class="nf">ShouldNot</span><span class="p">(</span><span class="nf">HaveOccurred</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Eventually</span><span class="p">(</span><span class="nx">session</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nx">gexec</span><span class="p">.</span><span class="nf">Exit</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">session</span><span class="p">.</span><span class="nx">Out</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nx">gbytes</span><span class="p">.</span><span class="nf">Say</span><span class="p">(</span><span class="s">`</span><span class="s">(?m)BuildVersion:.*\nBuildDate:</span><span class="s">`</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">session</span><span class="p">.</span><span class="nx">Err</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nx">gbytes</span><span class="p">.</span><span class="nf">Say</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nf">When</span><span class="p">(</span><span class="s">&#34;binary is used incorrectly&#34;</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nf">It</span><span class="p">(</span><span class="s">&#34;fails without any argument&#34;</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">command</span> <span class="o">:=</span> <span class="nx">exec</span><span class="p">.</span><span class="nf">Command</span><span class="p">(</span><span class="s">&#34;ci-build/r&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nx">session</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">gexec</span><span class="p">.</span><span class="nf">Start</span><span class="p">(</span><span class="nx">command</span><span class="p">,</span> <span class="nx">GinkgoWriter</span><span class="p">,</span> <span class="nx">GinkgoWriter</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="p">.</span><span class="nf">ShouldNot</span><span class="p">(</span><span class="nf">HaveOccurred</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Eventually</span><span class="p">(</span><span class="nx">session</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nx">gexec</span><span class="p">.</span><span class="nf">Exit</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">session</span><span class="p">.</span><span class="nx">Out</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nx">gbytes</span><span class="p">.</span><span class="nf">Say</span><span class="p">(</span><span class="s">&#34;usage: r &lt;path&gt; &lt;new_filename&gt;&#34;</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nf">Expect</span><span class="p">(</span><span class="nx">session</span><span class="p">.</span><span class="nx">Err</span><span class="p">)</span><span class="p">.</span><span class="nf">Should</span><span class="p">(</span><span class="nx">gbytes</span><span class="p">.</span><span class="nf">Say</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="p">)</span>
</span></span></code></pre>
<ul>
<li><code>Ordered</code> container caveat: When defining before scripts, the superior container (which is <code>When</code> in this case) needs to have the <code>Ordered</code> <a href="https://onsi.github.io/ginkgo/#ordered-containers">Decorator</a> set. Looking at their example, they assume that resources are reused outside of one <code>It</code>, as some variables are defined in the superior container. But I&rsquo;m not sure why it can&rsquo;t just run all before&rsquo;s in hierarchical order like rspec can do it&hellip;</li>
<li>Despite the previous point, there are before and after scripts for suite, all and each. It just lacks in rspec&rsquo;s <code>around</code>.</li>
</ul>

<h2>Thoughts<a id="thoughts"/></h2>

<p>The tested framework feels much more like rspec than the standard library testing framework. It looks promising for BDD-alike tests in go.
I&rsquo;ll keep an eye on that when implementing integration tests for my next go projects.</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1"><a href="https://en.wikipedia.org/wiki/Behavior-driven_development">Behavior-Driven-Development</a> having <a href="https://en.wikipedia.org/wiki/Given-When-Then">Given-When-Then</a>-alike structures.</li>

<li id="fn:2">Real as in it modifies the system environment by creating and removing files</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 23 Jan 2024 18:09:23 +0100</pubDate>
    </item>
    <item>
      <title>Continue interrupted uploads via dd</title>
      <link>https://evilcookie.de/continue-interrupted-uploads-via-dd.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Continue interrupted uploads via dd skip</h1>

<p><img src="continue-interrupted-uploads-via-dd_upload.jpg"/>
<small style="color:gray">Squirel in a London park. </small></p>

<p>While falling into <a href="https://github.com/Project-OSRM/osrm-backend">the routing engine rabbit hole</a> planing my next hiking trip via nextcloud maps, I needed to upload a big file to my server. Upload bandwidth sucked as it mostly does in Germany<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. Well <code>scp</code> is my friend I guess:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ scp jakobsweg.tar.gz root@my.server:~/
</span></span><span class="line"><span class="cl">lost connection
</span></span></code></pre>
<p>Oops, after ten minutes with slow progress, the upload suddenly stopped due to a connection error.</p>

<h2>Problem</h2>

<p>Unfortunately scp can&rsquo;t continue an interrupted upload. There are some StackOverflow solutions about using <a href="https://stackoverflow.com/a/20860920">rsync</a> but
<a href="https://superuser.com/a/421688">this</a> solution using dd with its skip option got my attention.</p>

<h2>Upload what&rsquo;s missing</h2>

<p><a href="https://superuser.com/a/421688">The solution</a> suggest to just skip the already written bytes and append the rest to the destination file. Since this command is from
the server perspective and my local machine is in a NAT&rsquo;ed network which isn&rsquo;t accessible from the www, I did the steps manually:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="c1"># checkout sizes of the source and aborted destination file</span>
</span></span><span class="line"><span class="cl">server $ ls jakobsweg.tar.gz
</span></span><span class="line"><span class="cl">-rw-r--r--  <span class="m">1</span> root root <span class="m">490766336</span> Jan <span class="m">14</span> 14:26 jakobsweg.tar.gz
</span></span><span class="line"><span class="cl"><span class="nb">local</span> $ ls jakobsweg.tar.gz
</span></span><span class="line"><span class="cl">-rw-r--r-- <span class="m">1</span> raphael raphael <span class="m">1102126303</span> Jan <span class="m">14</span> 14:18 jakobsweg.tar.gz
</span></span><span class="line"><span class="cl"><span class="nb">local</span> $ <span class="nv">UPLOADED</span><span class="o">=</span><span class="m">490766336</span>
</span></span><span class="line"><span class="cl"><span class="nb">local</span> $ <span class="nv">REMAINING</span><span class="o">=</span><span class="k">$((</span><span class="m">1102126303</span> <span class="o">-</span> <span class="nv">$UPLOADED</span><span class="k">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># copy source file locally but skip the already transmitted bytes, divide remaining by something to raise the blocksize</span>
</span></span><span class="line"><span class="cl"><span class="c1"># while copying with a blocksize takes ages, better fill up the filesystem alignment</span>
</span></span><span class="line"><span class="cl"><span class="nb">local</span> $ dd <span class="k">if</span><span class="o">=</span>jakobsweg.tar.gz <span class="nv">of</span><span class="o">=</span>jakobsweg.tar.gz.part2 <span class="nv">skip</span><span class="o">=</span><span class="nv">$UPLOADED</span> <span class="nv">count</span><span class="o">=</span><span class="k">$((</span><span class="nv">$REMAINING</span><span class="o">/</span><span class="m">1024</span><span class="o">)</span> <span class="nv">bs</span><span class="o">=</span><span class="m">1024</span> <span class="nv">status</span><span class="o">=</span>progress
</span></span><span class="line"><span class="cl"><span class="c1"># upload the remaining data as usual</span>
</span></span><span class="line"><span class="cl"><span class="nb">local</span> $ scp jakobsweg.tar.gz.part2 root@my.server:~/
</span></span><span class="line"><span class="cl"><span class="c1"># append the remaining data to the aborted file</span>
</span></span><span class="line"><span class="cl">remote $ cat jakobsweg.tar.gz.part2 &gt;&gt; jakobsweg.tar.gz
</span></span><span class="line"><span class="cl"><span class="c1"># compare checksum -&gt; tada</span>
</span></span><span class="line"><span class="cl"><span class="nb">local</span> $ shasum jakobsweg.tar.gz
</span></span><span class="line"><span class="cl">a8b00b334319932b5794595f3eafc1c5bedfaa35  jakobsweg.tar.gz
</span></span><span class="line"><span class="cl">remote $ shasum jakobsweg.tar.gz
</span></span><span class="line"><span class="cl">a8b00b334319932b5794595f3eafc1c5bedfaa35  jakobsweg.tar.gz
</span></span></code></pre>
<div class="footnotes">

<hr>

<ol>
<li id="fn:1">citation needed</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 15 Jan 2024 23:44:55 +0100</pubDate>
    </item>
    <item>
      <title>verbose v1.1.0-edit support</title>
      <link>https://evilcookie.de/verbose-v110-edit-support.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>verbose v1.1.0 - example and edit support</h1>

<p>I recently <a href="https://evilcookie.de/hola-docker-mucho-gusto.html">got a new motivation</a> to update my vocabulary service <a href="https://verbose.raphaelpour.de">verbose</a>.
Each word can have an example sentence together with its translation now. Verbose has also a new edit page.</p>

<h2>Example support</h2>

<p><img src="verbose-v110-edit-support_verbose1.png"/></p>

<p>When learning new words it could be useful to have a helpful example. This adds more context to the translation. Having an example
is also useful for learning a whole new language, <a href="https://evilcookie.de/hola-docker-mucho-gusto.html">like spanish in my case</a>. I barely know 100 words, where an example sentece would not only contain
one unknown/hard to remember word but multiple.</p>

<p>To follow the <a href="https://en.wikipedia.org/wiki/KISS_principle">KISS principle</a> together with my <a href="https://evilcookie.de/rework-of-verbose.html">I-only-add-a-word-per-month-and-view-it-once-a-day</a> use-case, I still use my json file and added two fields containing the original example sentence such as its translation.</p>

<h2>Edit support</h2>

<p><img src="verbose-v110-edit-support_verbose2.png"/></p>

<p>In the past, if I made a typo, I ssh&rsquo;ed to the server, opened the json file and corrected the word manually. However, having a new &ldquo;column&rdquo; which is initialy empty for each word, I felt the need of
edit each entry via the service itself. I&rsquo;ve added another site that just POST&rsquo;s the changes. Unfortunately I can&rsquo;t use PUT, which would be the right method to
modify a resource, since <a href="https://softwareengineering.stackexchange.com/a/211790">this is not allowed</a>.</p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 08 Jan 2024 13:02:41 +0100</pubDate>
    </item>
    <item>
      <title>Hola docker, mucho gusto</title>
      <link>https://evilcookie.de/hola-docker-mucho-gusto.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Hola docker, mucho gusto!<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></h1>

<p><img src="hola-docker-mucho-gusto_docker.png"/></p>

<p>I&rsquo;m currently learning Spanish for my next vacation<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>. While Duolingo does an impressive job of <a href="https://raw.studio/blog/how-duolingo-utilises-gamification/">gamifying the learning process</a>, I thought about
combining this fairly unknown world with one that I&rsquo;m familiar with.</p>

<p>I use Linux and its utils a lot. I like to read man pages and I know a bunch of them. Why not switch the system language to Spanish then?</p>

<p>Well, maybe because 100 words is not enough&hellip; but in a fire-and-forget environment like a virtual machine or Docker container, it should be safe.</p>

<h3>Contents</h3>

<ul>
<li><a href="#dockerfile">Dockerfile</a>

<ul>
<li><a href="#intermezzo">Intermezzo - Minimized containers</a></li>
</ul></li>
<li><a href="#groping">Groping in the dark, anticipating light</a>

<ul>
<li><a href="#apt-update">apt update</a></li>
<li><a href="#apropos">apropos .</a></li>
<li><a href="#man-bash">man bash</a></li>
</ul></li>
<li><a href="#learnings">Today I learned</a></li>
</ul>

<h2>Dockerfile<a id='dockerfile'/></h2>

<p>After some fiddling with <a href="https://www.man7.org/linux/man-pages/man1/locale.1.html"><code>locale</code></a> I came up with this Dockerfile:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">FROM ubuntu:latest
</span></span><span class="line"><span class="cl">RUN yes|unminimize
</span></span><span class="line"><span class="cl">RUN apt update &amp;&amp; \
</span></span><span class="line"><span class="cl">    DEBIAN_FRONTEND=noninteractive apt install -y locales \
</span></span><span class="line"><span class="cl">                                                  man-db \
</span></span><span class="line"><span class="cl">                                                  manpages-es \
</span></span><span class="line"><span class="cl">                                                  manpages-es-dev \
</span></span><span class="line"><span class="cl">                                                  language-pack-es
</span></span><span class="line"><span class="cl">RUN sed -i -e &#39;s/# en_US.UTF-8 UTF-8/es_ES.UTF-8 UTF-8/&#39; /etc/locale.gen &amp;&amp; \
</span></span><span class="line"><span class="cl">    dpkg-reconfigure --frontend=noninteractive locales &amp;&amp; \
</span></span><span class="line"><span class="cl">        update-locale LANG=es_ES.UTF-8
</span></span><span class="line"><span class="cl">ENV LANG es_ES.UTF-8
</span></span></code></pre>
<ul>
<li>unminimize Ubuntu container so man pages works</li>
<li>install man-db and their Spanish translations</li>
<li>install the language pack containing the translations for the system</li>
<li>replace the language where needed</li>
</ul>

<h3>Intermezzo - Minimized containers<a id='intermezzo'/></h3>

<p>Skip this if you just want to learn Spanish.</p>

<p>The Ubuntu container <a href="https://hub.docker.com/_/ubuntu"><em>[&hellip;] is a minimal install of Ubuntu[&hellip;]</em></a> and needs to get unminimized in order to be &ldquo;human-friendly&rdquo;.</p>

<p>Otherwise, <code>man bash</code> prints:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">This system has been minimized by removing packages and content that are
</span></span><span class="line"><span class="cl">not required on a system that users do not log into.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">To restore this content, including manpages, you can run the &#39;unminimize&#39;
</span></span><span class="line"><span class="cl">command. You will still need to ensure the &#39;man-db&#39; package is installed.
</span></span></code></pre>
<p>Actually <code>/usr/bin/man</code> is a bash script that only outputs this text.</p>

<p>What does the <code>unminimize</code> actually do? Tell me, <code>cat $(which unminimize)</code>: I&rsquo;ve put the output <a href="https://gist.github.com/RaphaelPour/e1a192beaae97f785033944ef96f4c83">into a gist</a>. It basically enabled documentation and man-pages again.</p>

<h2>Groping in the dark, anticipating light<a id='groping'/></h2>

<p>Those 100 words I know are more about traveling and less about updating Ubuntu packages&hellip;</p>

<p>But, hey, you know what the messages should be about and anticipate their translation.</p>

<h3>apt update<a id='apt-update'/></h3>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">root@1e7e70970891:/# apt update
</span></span><span class="line"><span class="cl">Des:1 http://security.ubuntu.com/ubuntu jammy-security InRelease [110 kB]
</span></span><span class="line"><span class="cl">Des:2 http://security.ubuntu.com/ubuntu jammy-security/universe amd64 Packages [1.046 kB]
</span></span><span class="line"><span class="cl">Obj:3 http://archive.ubuntu.com/ubuntu jammy InRelease
</span></span><span class="line"><span class="cl">Des:4 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [119 kB]
</span></span><span class="line"><span class="cl">Obj:5 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
</span></span><span class="line"><span class="cl">Des:6 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages [1.599 kB]
</span></span><span class="line"><span class="cl">Des:7 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 Packages [1.305 kB]
</span></span><span class="line"><span class="cl">Descargados 4.179 kB en 6s (755 kB/s)
</span></span><span class="line"><span class="cl">Leyendo lista de paquetes... Hecho
</span></span><span class="line"><span class="cl">Creando árbol de dependencias... Hecho
</span></span><span class="line"><span class="cl">Leyendo la información de estado... Hecho
</span></span><span class="line"><span class="cl">Todos los paquetes están actualizados.
</span></span></code></pre>
<ul>
<li><em>Hecho</em> must be something like &lsquo;done&rsquo;: it literaly means something like <em>fact</em> or <em>complete</em></li>
<li><em>dependencias</em> is easy:  dependencies</li>
<li><em>información</em> too: information</li>
</ul>

<h3>apropos .<a id='apropos'/></h3>

<p><code>apropos .</code> is a great way to display one tool per line, including a description<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>. Some favorites of mine:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">echo (1)             - muestra una línea de texto
</span></span><span class="line"><span class="cl">futex (7)            - bloqueos rápidos en espacio de usuario
</span></span><span class="line"><span class="cl">hostname (7)         - descripción de la resolución del nombre de equipo
</span></span><span class="line"><span class="cl">man (1)              - interfaz de los manuales de referencia del sistema
</span></span><span class="line"><span class="cl">memccpy (3)          - copia un área de memoria
</span></span><span class="line"><span class="cl">memcmp (3)           - compara areas de memoria
</span></span><span class="line"><span class="cl">memcpy (3)           - copiar area de memoria
</span></span><span class="line"><span class="cl">memmem (3)           - localiza una subcadena
</span></span><span class="line"><span class="cl">memmove (3)          - copia un área de memoria
</span></span><span class="line"><span class="cl">memset (3)           - rellena una zona de memoria con bytes repetidos
</span></span><span class="line"><span class="cl">md5sum (1)           - genera y verifica sumas de comprobación MD5
</span></span><span class="line"><span class="cl">stpcpy (3)           - copia una cadena devolviendo un apuntador a su final
</span></span><span class="line"><span class="cl">strcasecmp (3)       - comparan dos cadenas ignorando si son mayúsculas o minúsculas
</span></span><span class="line"><span class="cl">strstr (3)           - localiza una subcadena
</span></span><span class="line"><span class="cl">strchr (3)           - localizan un carácter en una cadena de ellos
</span></span><span class="line"><span class="cl">strdup (3)           - duplican una cadena de caracteres
</span></span><span class="line"><span class="cl">strlen (3)           - calcula la longitud de una cadena de caracteres
</span></span></code></pre>
<p>Especially all those C <em>mem*</em> and <em>str*</em> functions were fairly easy to anticipate when listed together:</p>

<ul>
<li><em>caracteres</em>: character, personality, both English and Spanish words seem to have the same origin, while both can be a &ldquo;written symbol&rdquo;, such as &ldquo;personality&rdquo;</li>
<li><em>copia</em>: copy</li>
<li><em>compara</em>: compare</li>
<li><em>interfaz</em>: interface</li>
<li><em>repetidos</em>: he repeats, male form of repetide</li>
<li><em>texto</em>: text</li>
<li><em>sumas</em>: you add, join</li>
</ul>

<h3>man bash<a id='man-bash'/></h3>

<p>Every time I accidentally look for the man page of a bash built-in, I get the huge bash man-page containing lots of essentials. In this case, this is exactly what we want.
It offers everything from abstract basics like lists, expressions and comparisons to more practical features like the actual built-in commands.</p>

<p>Some of my favorite entries:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">(lista)       lista se ejecuta en un subshell
</span></span><span class="line"><span class="cl">{ lista; }    lista se ejecuta en el entorno actual de la shell
</span></span><span class="line"><span class="cl">((expresión)) La expresión se evalúa de acuerdo a las reglas descritas abajo bajo la sección EVALUACIÓN ARITMÉTICA.
</span></span><span class="line"><span class="cl">
</span></span></code></pre>
<h2>Today I learned<a id='learnings'/></h2>

<table>
<thead>
<tr>
<th>es</th>
<th>en</th>
<th>example es</th>
<th>example en</th>
</tr>
</thead>

<tbody>
<tr>
<td>información</td>
<td>information</td>
<td>Yo tengo información.</td>
<td>I have information.</td>
</tr>

<tr>
<td>dependecias</td>
<td>dependencies</td>
<td>Vim necesite dependencias.</td>
<td>Vim needs dependencies.</td>
</tr>

<tr>
<td>memoria</td>
<td>memory</td>
<td>Copiar area de memoria.</td>
<td>Copy memory area.</td>
</tr>

<tr>
<td>caracteres</td>
<td>character, personality</td>
<td>ASCII tiene 128 characteres</td>
<td>ASCII has 128 characters.</td>
</tr>

<tr>
<td>copia</td>
<td>copy</td>
<td>El programa copia el texto.</td>
<td>The program copies the text.</td>
</tr>

<tr>
<td>compara</td>
<td>compare</td>
<td>Compara ambios programas</td>
<td>Compare both programs.</td>
</tr>

<tr>
<td>interfaz</td>
<td>interface</td>
<td>Está activa sur interfaz de eth0?</td>
<td>Is your eth0 interface up?</td>
</tr>

<tr>
<td>repetidos</td>
<td colspan="3">he repeats</td>
</tr>

<tr>
<td>texto</td>
<td>text</td>
<td>Soy un texto</td>
<td>I&rsquo;m a text.</td>
</tr>

<tr>
<td>sumas</td>
<td>you add, join</td>
<td>Él suma los números.</td>
<td>He adds the numbers.</td>
</tr>

<tr>
<td>hecho</td>
<td>done, complete, fact</td>
<td>Bien hecho!</td>
<td>Well done!</td>
</tr>
</tbody>
</table>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1"><em>Hello docker, nice to meet you</em></li>

<li id="fn:2">The caminho portugeś &ldquo;Jakobsweg&rdquo; (<a href="https://en.wikipedia.org/wiki/Camino_de_Santiago">Caminoh de Santiago</a>) with <a href="https://github.com/Tch1b0">Johannes</a>.</li>

<li id="fn:3">Where I still see a lot of English. Either I forgot some settings/packages, or the translation is still in progress.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Thu, 04 Jan 2024 17:50:36 +0100</pubDate>
    </item>
    <item>
      <title>hashsets in go</title>
      <link>https://evilcookie.de/hashsets-in-go.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Hashsets in go</h1>

<p><img src="hashsets-in-go_hashset.png"/></p>

<p>tl;dr</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">hashSet</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kd">struct</span><span class="p">{</span><span class="p">}</span>
</span></span></code></pre>
<h2>Introduction</h2>

<p>The term HashSet is a data structure from the <a href="https://docs.oracle.com/javase/8/docs/api/java/util/HashSet.html">Java universe</a> describing a value-less HashMap<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. It is perfect when uniqueness is needed but avoids the overhead of a value.
Using golang they can be constructed using an ordinary map and an empty struct:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">hashSet</span> <span class="kd">map</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="kd">struct</span><span class="p">{</span><span class="p">}</span>
</span></span></code></pre>
<h2>Use Cases</h2>

<p>The key can be any <a href="https://go.dev/ref/spec#MapType">supported type</a>. Interestingly, next to the primitive ones (<code>int</code>, <code>string</code>,&hellip;), struct types are also supported. This comes quite handy when making custom cache keys.</p>

<h3>Visited nodes</h3>

<p>When searching through a grid or a graph, a HashSet can be used to avoid loops by caching already seen points:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Point</span> <span class="kd">struct</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">x</span><span class="p">,</span><span class="nx">y</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">visited</span> <span class="kd">map</span><span class="p">[</span><span class="nx">Point</span><span class="p">]</span><span class="kd">struct</span><span class="p">{</span><span class="p">}</span>
</span></span></code></pre>
<h3>Uniqueness</h3>

<p>Another use-case would be to ensure uniqueness over a dataset. E.g. the bash command <code>uniq</code> reads a stream from stdin and only prints every line once to stdout:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;bufio&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;os&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">set</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kd">struct</span><span class="p">{</span><span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">scanner</span> <span class="o">:=</span> <span class="nx">bufio</span><span class="p">.</span><span class="nf">NewScanner</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stdin</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="nx">scanner</span><span class="p">.</span><span class="nf">Scan</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">found</span> <span class="o">:=</span> <span class="nx">set</span><span class="p">[</span><span class="nx">scanner</span><span class="p">.</span><span class="nf">Text</span><span class="p">(</span><span class="p">)</span><span class="p">]</span><span class="p">;</span> <span class="p">!</span><span class="nx">found</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">set</span><span class="p">[</span><span class="nx">scanner</span><span class="p">.</span><span class="nf">Text</span><span class="p">(</span><span class="p">)</span><span class="p">]</span> <span class="p">=</span> <span class="kd">struct</span><span class="p">{</span><span class="p">}</span><span class="p">{</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">scanner</span><span class="p">.</span><span class="nf">Text</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Turning&hellip;</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"> I&#39;ve experiments to run.
</span></span><span class="line"><span class="cl"> There is research to be done.
</span></span><span class="line"><span class="cl"> On the people who are
</span></span><span class="line"><span class="cl"> still alive.
</span></span><span class="line"><span class="cl"> And believe me I am
</span></span><span class="line"><span class="cl"> still alive.
</span></span><span class="line"><span class="cl"> I&#39;m doing science and I&#39;m
</span></span><span class="line"><span class="cl"> still alive.
</span></span><span class="line"><span class="cl"> I feel fantastic and I&#39;m
</span></span><span class="line"><span class="cl"> still alive.
</span></span><span class="line"><span class="cl"> While you&#39;re dying I&#39;ll be
</span></span><span class="line"><span class="cl"> still alive.
</span></span><span class="line"><span class="cl"> And when you&#39;re dead I will be
</span></span><span class="line"><span class="cl"> still alive.
</span></span></code></pre>
<p>&hellip;via <code>cat lyrics| go run unique.go</code> to&hellip;</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">I&#39;ve experiments to run.
</span></span><span class="line"><span class="cl">There is research to be done.
</span></span><span class="line"><span class="cl">On the people who are
</span></span><span class="line"><span class="cl">still alive.
</span></span><span class="line"><span class="cl">And believe me I am
</span></span><span class="line"><span class="cl">I&#39;m doing science and I&#39;m
</span></span><span class="line"><span class="cl">I feel fantastic and I&#39;m
</span></span><span class="line"><span class="cl">While you&#39;re dying I&#39;ll be
</span></span><span class="line"><span class="cl">And when you&#39;re dead I will be
</span></span></code></pre>
<h2>References</h2>

<ul>
<li><a href="https://github.com/RaphaelPour/aoc2023/blob/main/days/10/part.go#L138">example</a></li>
<li>Hashicorp go-package for more sophisticated HashSet usages: <a href="https://pkg.go.dev/github.com/hashicorp/go-set">go-set</a></li>
</ul>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Same as <code>map</code> in <a href="https://go.dev/blog/maps">golang</a>, <code>dict</code> in <a href="https://docs.python.org/3/tutorial/datastructures.html#dictionaries">python</a>, associative arrays in <a href="https://www.php.net/manual/en/language.types.array.php">php</a></li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Thu, 14 Dec 2023 14:15:50 +0100</pubDate>
    </item>
    <item>
      <title>how to rename files without specifying the path twice</title>
      <link>https://evilcookie.de/how-to-rename-files-without-specifying-the-path-twice.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>How to rename files without specifying the path twice</h1>

<p><img src="how-to-rename-files-without-specifying-the-path-twice_schweini.jpg"/></p>

<p>How to avoid <code>mv /this/is/a/long/path/to/my/guinea/pig/trfel.pig /this/is/a/long/path/to/my/guinea/pig/trueffel.pig</code> and just do something like <code>&lt;cmd&gt; /this/is/a/long/path/to/my/guinea/pig/trfel.file trueffel.pig</code>?</p>

<p>Maybe I&rsquo;m totally off today<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>, or this naive question hasn&rsquo;t a navie answer. Anyway, I couldn&rsquo;t come up
with a straight-forward solution within my bash<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>.</p>

<p>I&rsquo;d like to have an easy memorable solution without pattern matching or syntax.</p>

<h2>DIY</h2>

<p>I came up with my own renaming tool, just wrapping the <code>os.Rename</code> call with the right parameters:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;os&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;path/filepath&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">3</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;usage: r &lt;path&gt; &lt;new_filename&gt;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">newPath</span> <span class="o">:=</span> <span class="nx">filepath</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">filepath</span><span class="p">.</span><span class="nf">Dir</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">)</span><span class="p">,</span> <span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">os</span><span class="p">.</span><span class="nf">Rename</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">,</span> <span class="nx">newPath</span><span class="p">)</span><span class="p">;</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;error renaming %s to %s: %s\n&#34;</span><span class="p">,</span> <span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">,</span> <span class="nx">newPath</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;%s -&gt; %s\n&#34;</span><span class="p">,</span> <span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">,</span> <span class="nx">newPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Which works like:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">&gt; r /home/jane/dev/r/main.c main.go
</span></span><span class="line"><span class="cl">/home/jane/dev/r/main.c -&gt; /home/jane/dev/r/main.go
</span></span></code></pre>
<h2>SO solutions</h2>

<p>I found this <a href="https://unix.stackexchange.com/questions/132235/quickest-way-to-rename-files-without-retyping-directory-path">SO Post</a> afterwards, but wasn&rsquo;t satisfied. The <a href="https://unix.stackexchange.com/a/132237">acknowledged answer</a> using <code>mv</code> and brace-expansion only works if the suffix need to be renamed. The <a href="https://unix.stackexchange.com/a/132241">next answer</a> with <code>rename</code> is imo not intuitive. I just want to rename without any generic/pattern/expansion stuff.</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Like my guinea pig <em>Trüffel</em> (see feature image) who&rsquo;s waiting for the next kohlrabi feeding.</li>

<li id="fn:2">Please prove me wrong and show me an easy way feedback@evilcookie.de</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 15 Nov 2023 18:26:47 +0100</pubDate>
    </item>
    <item>
      <title>measure downtime durations via icmp</title>
      <link>https://evilcookie.de/measure-downtime-durations-via-icmp.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>measure downtime durations via icmp</h1>

<p><img src="measure-downtime-durations-via-icmp_downtime.jpg"/>
<small style="color:gray">Construction site at the Sendlinger Tor in Munich.</small></p>

<p>How long does it take for the failover mechanism to fail-over? How long does it take for my server to be up again?</p>

<p>I recently had the challenge of measuring downtime durations. <a href="https://linux.die.net/man/8/ping">ping</a> on the one hand &ldquo;makes me see&rdquo; when paket loss occurs and vanishes but lacks in aggregation. <a href="https://linux.die.net/man/8/mtr">mtr</a> on the other side aggregates the replies, but not for the metric I was looking for.</p>

<p>So I made up my own tool namely <a href="https://github.com/RaphaelPour/downtime"><code>downtime</code></a>. Aside the plain measurement logic, I tried a few new things like <em>external lib interfaces</em> and <em>mocks</em> which will shortly be addressed in the end.</p>

<ul>
<li><a href="#how-it-works">How it works</a></li>
<li><a href="#example">Example</a></li>
<li><a href="#design">Implementation design</a>

<ul>
<li><a href="#interface">External lib interface</a></li>
<li><a href="#mocks">Mocks</a></li>
<li><a href="#extensibility">Extensibility</a></li>
</ul></li>
</ul>

<h2>How it works<a id='how-it-works'/></h2>

<p>Ping the host via icmp using a customized timeout and a small interval to pinpoint the start and end timestamp of the downtime. This can then be used to calculate the duration.</p>

<p>The timeout should be as low as possible. The RTT of my service was not higher than 25ms, so 50ms timeout should be good to go. It should also tolerate some spikes that might appear randomly without falsifying our measurements. The interval should be pretty low and defines the error of the downtime.</p>

<p>The icmp logic is based on my colleagues <a href="https://github.com/tonobo/mtr">mtr</a> go-rewrite providing me <a href="https://github.com/tonobo/mtr/blob/master/pkg/icmp/icmp.go#L38">the most high-level icmp interface</a> I could find. This enables me to use raw icmp pakets without caring about the low level stuff like encoding the PID into the request body to fish out the corresponding replies from the ocean of icmp traffic.</p>

<h2>Example<a id='example'/></h2>

<p>To answer the second of the two initial questions &ldquo;How long does it take for my server to be up again after?&rdquo;:</p>

<ol>
<li>start downtime with server ip</li>
<li>restart server</li>
<li>wait until server is up again and downtime terminated</li>
</ol>

<p>For my cloud server with no further setup this took 17s:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ downtime --target 23.88.32.x
</span></span><span class="line"><span class="cl">start: 2023-09-22 12:27:31.751644064 +0200 CEST m=+11.151409405
</span></span><span class="line"><span class="cl">end: 2023-09-22 12:27:49.278929522 +0200 CEST m=+28.678694794
</span></span><span class="line"><span class="cl">duration: 17.527285389s
</span></span></code></pre>
<h2>Implementation design<a id='design'/></h2>

<p>Aside from the measurement logic, I tried a few things I&rsquo;ve learned over the years to improve extensibility and maintainability.</p>

<h3>External lib interface<a id='interface'/></h3>

<p>Define an interface for an external lib only containing needed functions. E.g. <a href="https://github.com/RaphaelPour/downtime/blob/main/icmp.go">icmp.go</a> for my dependency to <a href="https://github.com/tonobo/mtr/blob/master/pkg/icmp/icmp.go#L38">tonobo&rsquo;s SendICMP</a>. While beeing a bit verbose in the first place, it has two advantages:</p>

<ol>
<li>The dependency to the external lib is documented at one place. Usually you&rsquo;d need to scan the whole code base for the external lib to check whcih functions are in use.</li>
<li>Testing of complex external functions gets a lot easier. E.g. my unit test don&rsquo;t need to do real icmp stuff using mocks.</li>
</ol>

<h3>Mocks<a id='mocks'/></h3>

<p>Interfaces can easily be mocked using a lib like <a href="https://vektra.github.io/mockery/latest/">mockery</a>. E.g. <a href="https://github.com/RaphaelPour/downtime/blob/main/mocks/ICMP.go">icmp mock</a> for my <a href="https://github.com/RaphaelPour/downtime/blob/main/icmp.go">icmp interface</a>. As mentioned previously the mock can be used to test the lib without calling the external library. The goal of testing should be to test the <em>own</em> and not the <em>external</em> code.</p>

<h3>Extensibility<a id='extensibility'/></h3>

<p>I&rsquo;ve decided to provide the package as both: lib and binary. The only quirk is that the install url ends with <code>downtime/cmd/downtime</code>, but hence all people would copy the go install command from my readme anyway, it doesn&rsquo;t really matter.</p>

<p>In the end, the binary is just a specialized implementation of the watcher and reply checker. The watcher gets called two times: first time blocking until the first reply times out and the second time blocking until the first reply succeeds again. User of the lib can bend this my making they&rsquo;re own checker.</p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 22 Sep 2023 17:24:32 +0200</pubDate>
    </item>
    <item>
      <title>Godot Wild Jam 60</title>
      <link>https://evilcookie.de/godot-wild-jam-60.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Godot Wild Jam 60</h1>

<p><img src="godot-wild-jam-60_overview.png"/></p>

<p>We<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> participated at the <a href="https://itch.io/jam/godot-wild-jam-60">Godot Wild Jam #60</a> with the theme <em>malfunction</em> and submitted <a href="https://itch.io/jam/godot-wild-jam-60/rate/2225903">Rebot Roboot</a>: <em>Repair your robotic companion after a failed firmware update.</em></p>

<ul>
<li><a href="https://itch.io/jam/godot-wild-jam-60/rate/2225903">jam submission</a></li>
<li><a href="https://evilc00kie.itch.io/rebot-roboot">game</a></li>
<li><a href="https://github.com/Glow-Project/gwj-60">source</a></li>
<li>soundtrack: <a href="https://soundcloud.com/beathoevn/mandarin-marshmallow">Mandarin Marshmallow</a></li>
<li>one wildcard implemented:  <em>Mobius loop</em> Your game starts and ends at the same point.</li>
</ul>

<h3>Contents</h3>

<ul>
<li><a href="#idea">Idea</a></li>
<li><a href="#mechanics">Minigame mechanics</a>

<ul>
<li><a href="#wires">Wires</a></li>
<li><a href="#gates">Logic gates</a></li>
<li><a href="#optics">Optics</a></li>
<li><a href="#brain">Brain</a></li>
</ul></li>
<li><a href="#summary">Summary</a></li>
</ul>

<h2>Idea<a id='idea'/></h2>

<p>Your robotic companion has malfunctions after a failed firmware update and needs to be repaired. Each of the four malfunctions corresponds to one minigame that needs to be resolved in order to make the robot fully functional again.</p>

<p><img src="godot-wild-jam-60_lab.png"/></p>

<p>The main scene is a lab with monitors to toggle music and the boot sequence and a table with icons to all minigames. We decided to not immediately show the success of a mini game to increase the tension. The player can press reboot on the right monitor which triggers a test suite validating all minigames sequentially. If one validation fails, an error message is printed for a few seconds and all minigames were reset. Each minigame has its own validation function.</p>

<h2>Minigame mechanics <a id='mechanics'/></h2>

<h3>Wires <a id='wires'/></h3>

<p>Connect all the jacks pair-wise having the same color by drag-and-dropping wires.</p>

<p><img src="godot-wild-jam-60_wires.png"/></p>

<p>Each jack has a color and is instanciated within Godot. They get randomly positioned <a href="https://github.com/Glow-Project/gwj-60/blob/master/levels/wires/wires.gd#L23C1-L43C10">on startup</a> within the jack boundary aligned<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> to a grid via modulo (so they look more circuit alike):</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="c1"># Called when the node enters the scene tree for the first time.</span>
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="n">_ready</span><span class="p">(</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">var</span> <span class="n">taken</span> <span class="p">:</span><span class="n">Array</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="err">$</span><span class="n">Jacks</span><span class="o">.</span><span class="n">get_children</span><span class="p">(</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">node</span> <span class="o">=</span> <span class="n">node</span> <span class="k">as</span> <span class="n">Jack</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="n">true</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="n">var</span> <span class="n">x_offset</span> <span class="o">=</span> <span class="n">randi_range</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="err">$</span><span class="n">JackBoundary</span><span class="o">.</span><span class="n">position</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="err">$</span><span class="n">JackBoundary</span><span class="o">.</span><span class="n">shape</span><span class="o">.</span><span class="n">get_rect</span><span class="p">(</span><span class="p">)</span><span class="o">.</span><span class="n">size</span><span class="o">.</span><span class="n">x</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="err">$</span><span class="n">JackBoundary</span><span class="o">.</span><span class="n">position</span><span class="o">.</span><span class="n">x</span> <span class="o">+</span> <span class="err">$</span><span class="n">JackBoundary</span><span class="o">.</span><span class="n">shape</span><span class="o">.</span><span class="n">get_rect</span><span class="p">(</span><span class="p">)</span><span class="o">.</span><span class="n">size</span><span class="o">.</span><span class="n">x</span><span class="o">/</span><span class="mi">2</span>
</span></span><span class="line"><span class="cl">      <span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">var</span> <span class="n">y_offset</span> <span class="o">=</span> <span class="n">randi_range</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="err">$</span><span class="n">JackBoundary</span><span class="o">.</span><span class="n">position</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="err">$</span><span class="n">JackBoundary</span><span class="o">.</span><span class="n">shape</span><span class="o">.</span><span class="n">get_rect</span><span class="p">(</span><span class="p">)</span><span class="o">.</span><span class="n">size</span><span class="o">.</span><span class="n">y</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="err">$</span><span class="n">JackBoundary</span><span class="o">.</span><span class="n">position</span><span class="o">.</span><span class="n">y</span> <span class="o">+</span> <span class="err">$</span><span class="n">JackBoundary</span><span class="o">.</span><span class="n">shape</span><span class="o">.</span><span class="n">get_rect</span><span class="p">(</span><span class="p">)</span><span class="o">.</span><span class="n">size</span><span class="o">.</span><span class="n">y</span><span class="o">/</span><span class="mi">2</span>
</span></span><span class="line"><span class="cl">      <span class="p">)</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="n">var</span> <span class="n">new_position</span> <span class="o">=</span> <span class="n">Vector2</span><span class="p">(</span><span class="n">x_offset</span> <span class="o">-</span> <span class="n">x_offset</span> <span class="o">%</span> <span class="mi">20</span><span class="p">,</span><span class="n">y_offset</span> <span class="o">-</span> <span class="n">y_offset</span> <span class="o">%</span> <span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="ow">not</span> <span class="n">new_position</span> <span class="ow">in</span> <span class="n">taken</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">node</span><span class="o">.</span><span class="n">position</span> <span class="o">=</span> <span class="n">new_position</span>
</span></span><span class="line"><span class="cl">        <span class="n">taken</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">new_position</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span>
</span></span></code></pre>
<p>On clicking on a jack to start connecting two jacks, a new <a href="https://github.com/Glow-Project/gwj-60/blob/master/components/wires/Cable.gd"><code>Cable</code></a> node gets added to the cables list. Those cable is basically a <code>Line2D</code> which also preserves the start and end jack such as validator.
The fiddly part was the drag-and-drop logic within the <a href="https://github.com/Glow-Project/gwj-60/blob/master/levels/wires/wires.gd#L45">mouse event handler</a>:</p>

<ul>
<li>focus tracking: each jack is tracking its focus on its own using a collision shape and <code>Area2D</code>&rsquo;s <code>mouse_entered</code> and <code>mouse_exited</code> events</li>
<li>disconnect previous cables: if the player wants to start a new cable on a jack that is already connected, the previous cables get removed</li>
<li>jack sound: after clicking on a jack a randomly chosen &ldquo;plug-in&rdquo; sound gets played<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup></li>
<li>movement: as the mouse moves while having a cable connected to a starting jack, the end position of the cable is just set to the mouse cursor ones</li>
</ul>

<h4>Validation</h4>

<p>The <a href="https://github.com/Glow-Project/gwj-60/blob/master/levels/wires/wires.gd#L120">validator</a> for the wires minigame checks if there are enough cables connected (count of jacks/2) such as if the start and end <a href="https://github.com/Glow-Project/gwj-60/blob/master/components/wires/jack.gd"><code>Jack</code></a> of every cable has the same color:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">func</span> <span class="n">validate</span><span class="p">(</span><span class="p">)</span> <span class="o">-</span><span class="o">&gt;</span> <span class="n">String</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">var</span> <span class="n">children</span> <span class="o">:=</span> <span class="err">$</span><span class="n">Cables</span><span class="o">.</span><span class="n">get_children</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">children</span><span class="p">)</span> <span class="o">!=</span> <span class="err">$</span><span class="n">Jacks</span><span class="o">.</span><span class="n">get_child_count</span><span class="p">(</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">cables not connected</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="n">cable</span> <span class="ow">in</span> <span class="n">children</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">cable</span><span class="o">.</span><span class="n">source</span><span class="o">.</span><span class="n">modulate</span> <span class="o">!=</span> <span class="n">cable</span><span class="o">.</span><span class="n">destination</span><span class="o">.</span><span class="n">modulate</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">wrong connection</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">&#34;</span>
</span></span></code></pre>
<h3>Logic gates <a id='gates'/></h3>

<p>Flip the input bits so the output big becomes</p>

<p><img src="godot-wild-jam-60_gates2.png"/>
<img src="godot-wild-jam-60_gates.png"/></p>

<p>The logical circuit is a graph with <a href="https://github.com/Glow-Project/gwj-60/blob/master/components/logicgates/gate.gd"><code>Gate</code></a> nodes as nodes and <a href="https://github.com/Glow-Project/gwj-60/blob/master/components/logicgates/gateconnection.gd"><code>GateConnection</code></a> as edges. Both is instantiated within the Godot scene graph while the Gates can be placed within the scene and the GateConnections are automatically drawn on run-time. The graph is built using export variables of both Gates and GateConnections. Both nodes have an <code>output</code> function basically &ldquo;pulling&rdquo; the signal recursively from sink to source<sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="c1"># Gate.gd</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="n">output</span><span class="p">(</span><span class="p">)</span> <span class="o">-</span><span class="o">&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">match</span> <span class="nb">type</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">GateTypeEnum</span><span class="o">.</span><span class="n">ZERO</span><span class="p">:</span> <span class="k">return</span> <span class="n">false</span>
</span></span><span class="line"><span class="cl">    <span class="n">GateTypeEnum</span><span class="o">.</span><span class="n">ONE</span><span class="p">:</span> <span class="k">return</span> <span class="n">true</span>
</span></span><span class="line"><span class="cl">    <span class="n">GateTypeEnum</span><span class="o">.</span><span class="n">AND</span><span class="p">:</span> 
</span></span><span class="line"><span class="cl">      <span class="c1"># grab both inputs before doing the check</span>
</span></span><span class="line"><span class="cl">      <span class="c1"># in order to update both paths</span>
</span></span><span class="line"><span class="cl">      <span class="n">var</span> <span class="n">a</span> <span class="o">=</span> <span class="n">input1</span><span class="o">.</span><span class="n">output</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">var</span> <span class="n">b</span> <span class="o">=</span> <span class="n">input2</span><span class="o">.</span><span class="n">output</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="n">a</span> <span class="ow">and</span> <span class="n">b</span>
</span></span><span class="line"><span class="cl">    <span class="n">GateTypeEnum</span><span class="o">.</span><span class="n">OR</span><span class="p">:</span> 
</span></span><span class="line"><span class="cl">      <span class="n">var</span> <span class="n">a</span> <span class="o">=</span> <span class="n">input1</span><span class="o">.</span><span class="n">output</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">var</span> <span class="n">b</span> <span class="o">=</span> <span class="n">input2</span><span class="o">.</span><span class="n">output</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="n">a</span> <span class="ow">or</span> <span class="n">b</span>
</span></span><span class="line"><span class="cl">    <span class="n">GateTypeEnum</span><span class="o">.</span><span class="n">NOT</span><span class="p">:</span> <span class="k">return</span> <span class="err">!</span><span class="n">input1</span><span class="o">.</span><span class="n">output</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">GateTypeEnum</span><span class="o">.</span><span class="n">OUT</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="n">var</span> <span class="n">out</span> <span class="o">=</span> <span class="n">input1</span><span class="o">.</span><span class="n">output</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="err">!</span><span class="n">out</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">out_audio_played</span> <span class="o">=</span> <span class="n">false</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="err">!</span><span class="n">out_audio_played</span> <span class="ow">and</span> <span class="n">out</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">out_audio_played</span> <span class="o">=</span> <span class="n">true</span>
</span></span><span class="line"><span class="cl">        <span class="err">$</span><span class="n">OutAudio</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">update_texture</span><span class="p">(</span><span class="n">out</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="n">out</span>
</span></span><span class="line"><span class="cl">    <span class="n">GateTypeEnum</span><span class="o">.</span><span class="n">IN</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="n">update_texture</span><span class="p">(</span><span class="n">input_value</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="n">input_value</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="n">false</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># GateConnection.gd</span>
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="n">output</span><span class="p">(</span><span class="p">)</span> <span class="o">-</span><span class="o">&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">cached_out</span> <span class="o">=</span> <span class="n">source</span><span class="o">.</span><span class="n">output</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="n">cached_out</span>
</span></span></code></pre>
<ul>
<li>prefetching inputs: the inputs for <code>AND</code> and <code>OR</code> need to be fetched before evaluation to avoid <a href="https://en.wikipedia.org/wiki/Short-circuit_evaluation">short-circuit evaluation</a> where the second argument doesn&rsquo;t get evaluated if the first doesn&rsquo;t satisfy the expression.</li>
<li>signal caching: the GateConnection caches the output value, so its <code>process</code> can use it for coloring the cable</li>
<li>recursive updates: the output <a href="https://github.com/Glow-Project/gwj-60/blob/master/components/logicgates/gate.gd"><code>Gate</code></a> calls <code>output</code> periodically within its <code>process</code> to update all Gates and GateConnections</li>
</ul>

<h4>Validation</h4>

<p>It just needs to be checked if the output gate is set to 1.</p>

<h3>Optics<a id='optics'/></h3>

<p>Reflect the laser beam with the mirrors so the output block gets lit.</p>

<p><img src="godot-wild-jam-60_optics.png"/></p>

<p>The mirrors are essentially rotatable collision shapes. The path of the laser beam is continuously recalculated within the <a href="https://github.com/Glow-Project/gwj-60/blob/master/levels/optics/optics.gd#L14">minigame&rsquo;s <code>process</code></a> using a <a href="https://docs.godotengine.org/en/stable/classes/class_raycast2d.html"><code>RayCast2D</code></a>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">func</span> <span class="n">_process</span><span class="p">(</span><span class="n">delta</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># clear the laser beam</span>
</span></span><span class="line"><span class="cl">  <span class="err">$</span><span class="n">LaserBeam</span><span class="o">.</span><span class="n">clear_points</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># let the lazer beam start at the position of the emitter</span>
</span></span><span class="line"><span class="cl">  <span class="err">$</span><span class="n">LaserBeam</span><span class="o">.</span><span class="n">add_point</span><span class="p">(</span><span class="err">$</span><span class="n">Emitter</span><span class="o">.</span><span class="n">global_position</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="c1"># position the ray cast initially to the emitters position</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># pointing to the right towards the first mirror</span>
</span></span><span class="line"><span class="cl">  <span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">global_position</span> <span class="o">=</span> <span class="err">$</span><span class="n">Emitter</span><span class="o">.</span><span class="n">global_position</span>
</span></span><span class="line"><span class="cl">  <span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">target_position</span> <span class="o">=</span> <span class="n">Vector2</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="n">var</span> <span class="n">reflect_target</span><span class="p">:</span> <span class="n">Vector2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># loop as long as the raycast hits a mirror</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># and break if it collides with the output block or with nothing at all</span>
</span></span><span class="line"><span class="cl">  <span class="k">while</span> <span class="n">true</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="c1"># force the ray cast to walk from the global position towards the target</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># finding the first collision (or none if there is nothing to collide with)</span>
</span></span><span class="line"><span class="cl">    <span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">force_raycast_update</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># if ray cast points beyond the minigame window bounds, no collission will happen</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="err">!</span><span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">is_colliding</span><span class="p">(</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="err">$</span><span class="n">LightSink</span><span class="o">.</span><span class="n">unhighlight</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="err">$</span><span class="n">LaserBeam</span><span class="o">.</span><span class="n">add_point</span><span class="p">(</span><span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">global_position</span> <span class="o">+</span> <span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">target_position</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">break</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1"># we know that we&#39;ve collided with something, so add the point to the</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># laser beam</span>
</span></span><span class="line"><span class="cl">    <span class="err">$</span><span class="n">LaserBeam</span><span class="o">.</span><span class="n">add_point</span><span class="p">(</span><span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">get_collision_point</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">get_collider</span><span class="p">(</span><span class="p">)</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">WallArea</span><span class="s2">&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="k">break</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="c1"># the output block has been reached!</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">get_collider</span><span class="p">(</span><span class="p">)</span> <span class="o">==</span> <span class="err">$</span><span class="n">LightSink</span><span class="o">/</span><span class="n">Area2D</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="err">$</span><span class="n">LightSink</span><span class="o">.</span><span class="n">highlight</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">break</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1"># let the laser beam bounce of the mirror inspired by</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># https://github.com/Remysaurus/GodotReflectingLaser3D/blob/main/addons/laserGit/laser.gd#L75</span>
</span></span><span class="line"><span class="cl">    <span class="n">reflect_target</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">get_collision_point</span><span class="p">(</span><span class="p">)</span> <span class="o">-</span> <span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">global_position</span>
</span></span><span class="line"><span class="cl">      <span class="p">)</span><span class="o">.</span><span class="n">bounce</span><span class="p">(</span><span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">get_collision_normal</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># place the ray cast to collission point so the next iteration can find the next collision</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># add a small offset towards the target, otherwise the raycast will immediately collide</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># with the previous mirror</span>
</span></span><span class="line"><span class="cl">    <span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">global_position</span> <span class="o">=</span> <span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">get_collision_point</span><span class="p">(</span><span class="p">)</span> <span class="o">+</span> <span class="n">reflect_target</span><span class="o">.</span><span class="n">normalized</span><span class="p">(</span><span class="p">)</span><span class="o">*</span><span class="mi">2</span>
</span></span><span class="line"><span class="cl">    <span class="err">$</span><span class="n">RayCast</span><span class="o">.</span><span class="n">target_position</span> <span class="o">=</span> <span class="n">reflect_target</span><span class="o">.</span><span class="n">normalized</span><span class="p">(</span><span class="p">)</span><span class="o">*</span><span class="mi">300</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="err">$</span><span class="n">LaserSoundPlayer</span><span class="o">.</span><span class="n">pitch_scale</span> <span class="o">=</span> <span class="n">log</span><span class="p">(</span><span class="err">$</span><span class="n">LaserBeam</span><span class="o">.</span><span class="n">points</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="o">*</span><span class="mi">2</span>
</span></span></code></pre>
<p>Additionally the last line increases the pitch of the &ldquo;laser sound&rdquo; for each mirror which got hit by the laser.</p>

<h4>Validation</h4>

<p>The validate just need to look if the output block (aka light sink) is lit:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">func</span> <span class="n">validate</span><span class="p">(</span><span class="p">)</span> <span class="o">-</span><span class="o">&gt;</span> <span class="n">String</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">&#34;</span> <span class="k">if</span> <span class="err">$</span><span class="n">LightSink</span><span class="o">.</span><span class="n">highlighted</span> <span class="k">else</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">target did not receive laser beam</span><span class="s2">&#34;</span>
</span></span></code></pre>
<h3>Brain<a id='brain'/></h3>

<p>Dial the knobs so that the robot redraws the house. The brain aka visual cortex memes an image-detection program that tries to redraw the seen image as accurate as possible.</p>

<p><img src="godot-wild-jam-60_brain2.gif"/>
<img src="godot-wild-jam-60_brain.png"/></p>

<p>The house is manually drawn within godot using a <code>Line2D</code>, called <code>GoalLine</code>. The <code>RobotLine</code> consists of all points from <code>GoalLine</code> but transformed using values from the dial:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">update_robot_line</span><span class="p">(</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="err">$</span><span class="n">RobotLine</span><span class="o">.</span><span class="n">clear_points</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="n">var</span> <span class="n">index</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="n">point</span> <span class="ow">in</span> <span class="err">$</span><span class="n">GoalLine</span><span class="o">.</span><span class="n">points</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">point</span> <span class="o">=</span> <span class="n">point</span> <span class="k">as</span> <span class="n">Vector2</span>
</span></span><span class="line"><span class="cl">    <span class="n">var</span> <span class="n">robotPoint</span> <span class="o">=</span> <span class="n">point</span><span class="o">.</span><span class="n">rotated</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="nb">float</span><span class="p">(</span> <span class="err">$</span><span class="n">KnobA</span><span class="o">.</span><span class="n">value</span><span class="p">(</span><span class="p">)</span><span class="p">)</span> <span class="o">/</span> <span class="mi">50</span>
</span></span><span class="line"><span class="cl">      <span class="p">)</span> <span class="o">*</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="nb">float</span><span class="p">(</span><span class="err">$</span><span class="n">KnobB</span><span class="o">.</span><span class="n">value</span><span class="p">(</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">index</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="n">robotPoint</span> <span class="o">+</span><span class="o">=</span> <span class="n">Vector2</span><span class="p">(</span><span class="err">$</span><span class="n">KnobC</span><span class="o">.</span><span class="n">value</span><span class="p">(</span><span class="p">)</span> <span class="o">+</span> <span class="mf">0.3</span><span class="p">,</span> <span class="err">$</span><span class="n">KnobC</span><span class="o">.</span><span class="n">value</span><span class="p">(</span><span class="p">)</span> <span class="o">+</span> <span class="mf">0.2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="n">robotPoint</span> <span class="o">-</span><span class="o">=</span> <span class="n">Vector2</span><span class="p">(</span><span class="err">$</span><span class="n">KnobC</span><span class="o">.</span><span class="n">value</span><span class="p">(</span><span class="p">)</span> <span class="o">-</span> <span class="mf">0.3</span><span class="p">,</span> <span class="err">$</span><span class="n">KnobC</span><span class="o">.</span><span class="n">value</span><span class="p">(</span><span class="p">)</span> <span class="o">-</span> <span class="mf">0.2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="err">$</span><span class="n">RobotLine</span><span class="o">.</span><span class="n">add_point</span><span class="p">(</span><span class="n">robotPoint</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">index</span> <span class="o">+</span><span class="o">=</span> <span class="mi">1</span>
</span></span></code></pre>
<p>While the transformations of translating, scaling and rotating was intended, we needed to guess the coefficients to keep the transformation mostly within the viewport.
Within the <a href="https://github.com/Glow-Project/gwj-60/blob/master/levels/brain/brain.gd#L27">minigames <code>process</code></a>, the <code>RobotLine</code> gets transformed to the <code>ShowLine</code> which is the red &ldquo;cathode ray tube&rdquo;-alike Line2D that is actually shown to the player:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">func</span> <span class="n">_process</span><span class="p">(</span><span class="n">delta</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="n">last_update</span> <span class="o">+</span> <span class="n">delta</span> <span class="o">&lt;</span> <span class="mf">0.1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">last_update</span> <span class="o">+</span><span class="o">=</span> <span class="n">delta</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="n">last_update</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="n">point_index</span> <span class="o">&gt;</span><span class="o">=</span> <span class="err">$</span><span class="n">RobotLine</span><span class="o">.</span><span class="n">points</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="p">)</span><span class="o">-</span><span class="mi">2</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">point_index</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="err">$</span><span class="n">RobotLine</span><span class="o">.</span><span class="n">get_point_count</span><span class="p">(</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="err">$</span><span class="n">ShowLine</span><span class="o">.</span><span class="n">add_point</span><span class="p">(</span><span class="err">$</span><span class="n">RobotLine</span><span class="o">.</span><span class="n">get_point_position</span><span class="p">(</span><span class="n">point_index</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="err">$</span><span class="n">ShowLine</span><span class="o">.</span><span class="n">add_point</span><span class="p">(</span><span class="err">$</span><span class="n">RobotLine</span><span class="o">.</span><span class="n">get_point_position</span><span class="p">(</span><span class="n">point_index</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="err">$</span><span class="n">ShowLine</span><span class="o">.</span><span class="n">points</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="p">)</span><span class="o">-</span><span class="mi">5</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="err">$</span><span class="n">ShowLine</span><span class="o">.</span><span class="n">remove_point</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="n">point_index</span> <span class="o">+</span><span class="o">=</span> <span class="mi">1</span>
</span></span></code></pre>
<ul>
<li>speed control: to avoid stroboscopic effects and keep a constant speed the process is only executed every 100ms by tracking the last update</li>
<li>show only three points: this could&rsquo;ve been implemented easier but a globally tracked <code>point_index</code> is used to add only three points starting from the the index. The index gets incremented so the next iteration will proceed within the Line2D.</li>
</ul>

<h4>Validation</h4>

<p>This is the trickiest validation, as it is hard to exactly match the given line as dialing the knobs is a bit difficult. In order to keep the player&rsquo;s frustration rate low, the transformed points should match within a given error.</p>

<p>Since the order of the original and the transformed points is preserved, we know that ideally both lines should exactly match. To ease the process, we <a href="https://github.com/Glow-Project/gwj-60/blob/master/levels/brain/brain.gd#L77">calculate a pair-wise distance</a> and check if it is lower than a predefined tolerance:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">func</span> <span class="n">validate</span><span class="p">(</span><span class="p">)</span> <span class="o">-</span><span class="o">&gt;</span> <span class="n">String</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">const</span> <span class="n">TOLERANCE</span> <span class="o">=</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl">  <span class="n">var</span> <span class="n">player</span><span class="p">:</span> <span class="n">Line2D</span> <span class="o">=</span> <span class="err">$</span><span class="n">RobotLine</span>
</span></span><span class="line"><span class="cl">  <span class="n">var</span> <span class="n">goal</span><span class="p">:</span> <span class="n">Line2D</span> <span class="o">=</span> <span class="err">$</span><span class="n">GoalLine</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">player</span><span class="o">.</span><span class="n">get_point_count</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">var</span> <span class="n">p_pos</span> <span class="o">:=</span> <span class="n">player</span><span class="o">.</span><span class="n">get_point_position</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">var</span> <span class="n">g_pos</span> <span class="o">:=</span> <span class="n">goal</span><span class="o">.</span><span class="n">get_point_position</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">p_pos</span><span class="o">.</span><span class="n">distance_to</span><span class="p">(</span><span class="n">g_pos</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">TOLERANCE</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">image not aligned</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">&#34;</span>
</span></span></code></pre>
<h2>Summary<a id='summary'/></h2>

<p>It was great fun doing different minigames within one week. They had all different challenges which solutions I now can add to my Godot skills:</p>

<ul>
<li>wires: drag and drop</li>
<li>logic gates: implementing graphs and recursive evaluation</li>
<li>optics: ray casting</li>
<li>brain: connecting dials with a transformation matrix and animate a &ldquo;slow cathode ray tube&rdquo;</li>
</ul>

<p>The logic gates could be more simple by moving the connection into the gate. The Gates could just track where they get their input/s from and draw the connection <code>Line2D</code> by themselves.</p>

<p>Developing the optics minigame was most enjoyable since could finally get my hands dirty with ray tracing and also got the most positive feedback from friends and <a href="https://itch.io/jam/godot-wild-jam-60/rate/2225903">itch.io</a>.</p>

<p>Finally it was a pleasure to make all the textures and music by our own together with Johannes. I&rsquo;m looking forward for upcoming Pour Entertainment ssubmissions!</p>

<p>At the very end I&rsquo;ll give you some insight about our manual review issue tracking:</p>

<p><img src="godot-wild-jam-60_manual_issue_tracking.png"/></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1"><a href="https://github.com/Tch1b0">Johannes</a> and I</li>

<li id="fn:2">Well, they also have a non-deterministic while loop preventing overlapping jacks.</li>

<li id="fn:3">I recorded them while pluging some eurorack cables in and out.</li>

<li id="fn:4">While writing this it remembers me a little bit of ray tracing.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Thu, 24 Aug 2023 15:26:01 +0200</pubDate>
    </item>
    <item>
      <title>linux file observability</title>
      <link>https://evilcookie.de/linux-file-observability.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>linux file observability</h1>

<p><img src="linux-file-observability_observability.png"/></p>

<p>In linux, &ldquo;everything&rdquo; is a file<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. Regardless if its a regular file, directory, socket or even a device.
Know how to observe open files, attached to a process, can become quite handy for debugging a linux host.</p>

<ul>
<li><a href="#files-and-file-descriptors">Files and file descriptors</a></li>
<li><a href="#observe">Observe</a>

<ul>
<li><a href="#which-process">Wich process opened the file?</a></li>
<li><a href="#which-files">Which files do a process holding?</a><sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup></li>
<li><a href="#incoming-connections">Is my server already listening for incoming connections?</a></li>
<li><a href="#deleted-files">Does my process still hold fds to deleted files?</a></li>
</ul></li>
</ul>

<p>The first theoretical part will introduce file descriptors while the second part will give some practical examples.</p>

<h2>Files and file descriptors<a id="files-and-file-descriptors"/></h2>

<p>Whenever a program opens a file via a syscall from the <a href="https://man7.org/linux/man-pages/man2/open.2.html">open()</a> family,
the kernel returns a reference number that is unique for that process. This number is bettern known as file descriptor or fd for short. The program can act on that file (read, write, close,&hellip;) by using the fd from the open call.</p>

<p>Imagine a program like this:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="c1">// gcc example.c -o example
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;fcntl.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">arc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[</span><span class="p">]</span><span class="p">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">open</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">example.c</span><span class="s">&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="p">{</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span><span class="p">;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>This program will open a file (itself for simplicity) and goes into an infinite loop in order to stay alive for observability.</p>

<p>On <code>open</code> the system creates a procfs entry under <code>/proc/&lt;pid&gt;/fds/&lt;fd&gt;</code> . Listing the proc dir for our process<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup> looks something like this:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ ls -la /proc/1234/fd
</span></span><span class="line"><span class="cl">total <span class="m">0</span>
</span></span><span class="line"><span class="cl">dr-x------ <span class="m">2</span> raphael raphael  <span class="m">0</span> Jun <span class="m">29</span> 21:11 .
</span></span><span class="line"><span class="cl">dr-xr-xr-x <span class="m">9</span> raphael raphael  <span class="m">0</span> Jun <span class="m">29</span> 21:11 ..
</span></span><span class="line"><span class="cl">lrwx------ <span class="m">1</span> raphael raphael <span class="m">64</span> Jun <span class="m">29</span> 21:11 <span class="m">0</span> -&gt; /dev/pts/0
</span></span><span class="line"><span class="cl">lrwx------ <span class="m">1</span> raphael raphael <span class="m">64</span> Jun <span class="m">29</span> 21:11 <span class="m">1</span> -&gt; /dev/pts/0
</span></span><span class="line"><span class="cl">lrwx------ <span class="m">1</span> raphael raphael <span class="m">64</span> Jun <span class="m">29</span> 21:11 <span class="m">2</span> -&gt; /dev/pts/0
</span></span><span class="line"><span class="cl">lr-x------ <span class="m">1</span> raphael raphael <span class="m">64</span> Jun <span class="m">29</span> 21:11 <span class="m">3</span> -&gt; /tmp/example.c
</span></span></code></pre>
<h2>Observe</h2>

<h3>Wich process opened the file?<a id='which-process'/></h3>

<p><a href="https://linux.die.net/man/8/lsof"><code>lsof</code></a> got you covered:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ lsof /tmp/example
</span></span><span class="line"><span class="cl">COMMAND PID  USER  FD   TYPE DEVICE SIZE/OFF     NODE NAME
</span></span><span class="line"><span class="cl">example 444 raphael txt    REG   0,40    23656 26759037 /tmp/example
</span></span></code></pre>
<h3>Which files do a process holding?<a id='which-files'/></h3>

<p>It&rsquo;s <code>lsof</code> again. The opened <code>example.c</code> can be seen at last with fd 3 linking to the original file. The other three fd&rsquo;s 0 , 1  and 2  are the three <a href="https://man7.org/linux/man-pages/man4/pts.4.html">pts</a> devices for stdin, stdout stderr that get automatically created by the OS for any new process.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ lsof -p <span class="m">444</span>
</span></span><span class="line"><span class="cl">COMMAND PID    USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
</span></span><span class="line"><span class="cl">example <span class="m">444</span> raphael  cwd    DIR   8,32     <span class="m">4096</span> <span class="m">267422</span> /tmp/
</span></span><span class="line"><span class="cl">example <span class="m">444</span> raphael  rtd    DIR   8,32     <span class="m">4096</span>      <span class="m">2</span> /
</span></span><span class="line"><span class="cl">example <span class="m">444</span> raphael  txt    REG   8,32    <span class="m">16088</span>  <span class="m">46778</span> /tmp/example
</span></span><span class="line"><span class="cl">example <span class="m">444</span> raphael  mem    REG   8,32  <span class="m">2029592</span> <span class="m">142704</span> /usr/lib/...
</span></span><span class="line"><span class="cl">example <span class="m">444</span> raphael  mem    REG   8,32   <span class="m">191504</span> <span class="m">142576</span> /usr/lib/...
</span></span><span class="line"><span class="cl">example <span class="m">444</span> raphael    0u   CHR  136,0      0t0      <span class="m">3</span> /dev/pts/0
</span></span><span class="line"><span class="cl">example <span class="m">444</span> raphael    1u   CHR  136,0      0t0      <span class="m">3</span> /dev/pts/0
</span></span><span class="line"><span class="cl">example <span class="m">444</span> raphael    2u   CHR  136,0      0t0      <span class="m">3</span> /dev/pts/0
</span></span><span class="line"><span class="cl">example <span class="m">444</span> raphael    3r   REG   8,32      <span class="m">196</span>  <span class="m">46772</span> /tmp/example.c
</span></span></code></pre>
<h3>Is my server already listening for incoming connections?<a id='incoming-connections'/></h3>

<p>Let&rsquo;s spin up a tcp server waiting for incoming connections using <a href="https://www.man7.org/linux/man-pages/man1/ncat.1.html"><code>ncat</code></a>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ ncat -l <span class="m">8080</span>
</span></span></code></pre>
<p>Using <code>lsof</code> again, we can observe that <code>ncat</code> is even doing dual-stack waiting for incoming ipv4 and ipv6 connections, as one can see in the forelast entries.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ lsof -p <span class="m">532581</span>
</span></span><span class="line"><span class="cl">COMMAND    PID  USER   FD   TYPE             DEVICE SIZE/OFF     NODE NAME
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael  cwd    DIR               0,40      <span class="m">450</span> <span class="m">27369190</span> /tmp/example
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael  rtd    DIR               0,38      <span class="m">206</span>      <span class="m">256</span> /
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael  txt    REG               0,38   <span class="m">435520</span>  <span class="m">9123417</span> /usr/bin/ncat
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael  mem    REG               0,36           <span class="m">9123417</span> /usr/bin/ncat <span class="o">(</span>path <span class="nv">dev</span><span class="o">=</span>0,38<span class="o">)</span>
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael  mem    REG               0,36           <span class="m">9000771</span> /usr/lib64/...
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael    0u   CHR              136,1      0t0        <span class="m">4</span> /dev/pts/1
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael    1u   CHR              136,1      0t0        <span class="m">4</span> /dev/pts/1
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael    2u   CHR              136,1      0t0        <span class="m">4</span> /dev/pts/1
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael    3u  IPv6            <span class="m">9561146</span>      0t0      TCP *:webcache <span class="o">(</span>LISTEN<span class="o">)</span>
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael    4u  IPv4            <span class="m">9561147</span>      0t0      TCP *:webcache <span class="o">(</span>LISTEN<span class="o">)</span>
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael    6u  unix 0x0000000014cd383f      0t0    <span class="m">31426</span> <span class="nv">type</span><span class="o">=</span>STREAM <span class="o">(</span>CONNECTED<span class="o">)</span>
</span></span></code></pre>
<p>Let&rsquo;s go one step further and establish a connection to <code>ncat</code> by browsing to <code>localhost:8080</code>. We can see that <code>ncat</code>
closed the unused listener and from which address+port the connection is coming from:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ lsof -p <span class="m">532581</span>
</span></span><span class="line"><span class="cl">COMMAND    PID  USER   FD   TYPE             DEVICE SIZE/OFF     NODE NAME
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael  cwd    DIR               0,40      <span class="m">450</span> <span class="m">27369190</span> /tmp/example
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael  rtd    DIR               0,38      <span class="m">206</span>      <span class="m">256</span> /
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael  txt    REG               0,38   <span class="m">435520</span>  <span class="m">9123417</span> /usr/bin/ncat
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael  mem    REG               0,36           <span class="m">9123417</span> /usr/bin/ncat <span class="o">(</span>path <span class="nv">dev</span><span class="o">=</span>0,38<span class="o">)</span>
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael  mem    REG               0,36           <span class="m">9000771</span> /usr/lib64/...
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael    0u   CHR              136,1      0t0        <span class="m">4</span> /dev/pts/1
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael    1u   CHR              136,1      0t0        <span class="m">4</span> /dev/pts/1
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael    2u   CHR              136,1      0t0        <span class="m">4</span> /dev/pts/1
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael    5u  IPv4            <span class="m">9557641</span>      0t0      TCP localhost:webcache-&gt;localhost:32886 <span class="o">(</span>ESTABLISHED<span class="o">)</span>
</span></span><span class="line"><span class="cl">ncat    <span class="m">532581</span> raphael    6u  unix 0x0000000014cd383f      0t0    <span class="m">31426</span> <span class="nv">type</span><span class="o">=</span>STREAM <span class="o">(</span>CONNECTED<span class="o">)</span>
</span></span></code></pre>
<h3>Does my process still hold fds to deleted files?<a id="deleted-files"/></h3>

<p>Let&rsquo;s create a file and immediately <a href="https://www.man7.org/linux/man-pages/man2/unlink.2.html"><code>unlink</code></a> it but keep it open:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="c1">// gcc ulink.c -o ulink
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;fcntl.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[</span><span class="p">]</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">open</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">test.log</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">O_CREAT</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">unlink</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">test.log</span><span class="s">&#34;</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="p">{</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span><span class="p">;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>The file is not existent, but can be observed via <code>lsof</code>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ lsof -p <span class="m">635</span>
</span></span><span class="line"><span class="cl">COMMAND PID    USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
</span></span><span class="line"><span class="cl">ulink   <span class="m">635</span> raphael  cwd    DIR   8,32     <span class="m">4096</span> <span class="m">267422</span> /tmp/example
</span></span><span class="line"><span class="cl">ulink   <span class="m">635</span> raphael  rtd    DIR   8,32     <span class="m">4096</span>      <span class="m">2</span> /
</span></span><span class="line"><span class="cl">ulink   <span class="m">635</span> raphael  txt    REG   8,32    <span class="m">16168</span>  <span class="m">50490</span> /tmp/example
</span></span><span class="line"><span class="cl">ulink   <span class="m">635</span> raphael  mem    REG   8,32  <span class="m">2029592</span> <span class="m">142704</span> /usr/lib/...
</span></span><span class="line"><span class="cl">ulink   <span class="m">635</span> raphael    0u   CHR  136,0      0t0      <span class="m">3</span> /dev/pts/0
</span></span><span class="line"><span class="cl">ulink   <span class="m">635</span> raphael    1u   CHR  136,0      0t0      <span class="m">3</span> /dev/pts/0
</span></span><span class="line"><span class="cl">ulink   <span class="m">635</span> raphael    2u   CHR  136,0      0t0      <span class="m">3</span> /dev/pts/0
</span></span><span class="line"><span class="cl">ulink   <span class="m">635</span> raphael    3r   REG   8,32        <span class="m">0</span>  <span class="m">40397</span> /tmp/test.log <span class="o">(</span>deleted<span class="o">)</span>
</span></span></code></pre>
<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Rabbit hole warning! <a href="https://web.archive.org/web/20150110114929/http://ph7spot.com:80/musings/in-unix-everything-is-a-file">source based on wikipedia</a></li>

<li id="fn:2">Yes, I am looking at you <a href="https://stackoverflow.com/questions/8684609/where-can-i-find-php-ini">PHP</a>!</li>

<li id="fn:3">use &ldquo;prgrep -f example&rdquo; to get the pid</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 19 Jul 2023 12:30:00 +0200</pubDate>
    </item>
    <item>
      <title>blog update: customization</title>
      <link>https://evilcookie.de/blog-update-customization.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>blog update: customization</h1>

<p><img src="blog-update-customization_berlin.jpg"/>
<small style="color:gray">Berlin skyline at sunset from a rooftop.</small></p>

<p>Make your own customized blog using blogctl!</p>

<p>With <a href="https://github.com/RaphaelPour/blogctl/releases/tag/v1.0.0">blogctl v1.0.0</a>, all personal hard coded information are now configurable.
They can be specified using the introduced <code>blog.json</code> in the root of the blog directory:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;author&#34;</span><span class="p">:</span> <span class="s2">&#34;Raphael Pour&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;blog&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;domain&#34;</span><span class="p">:</span><span class="s2">&#34;evilcookie.de&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Hi, I&#39;m Raphael. I write about my software developer journey...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;footer&#34;</span><span class="p">:</span> <span class="s2">&#34;&lt;a href=&#39;rss.xml&#39;&gt;RSS&lt;/a&gt;|&lt;a href=&#39;impressum.html&#39;&gt;Impressum&lt;/a&gt;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<h2>text/template vs. html/template</h2>

<p>The index template gets now rendered using the <a href="https://pkg.go.dev/text/template">text/template</a> lib rather than <a href="https://pkg.go.dev/html/template">html/template</a> while the later escapes all
data parameters due to its <a href="https://pkg.go.dev/html/template#hdr-Security_Model">security model</a>. Escaping e.g. the RSS or impressum link would result in unusable ones.</p>

<p><code>text/html</code> doesn&rsquo;t care while template and arguments are trusted by default.</p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 12 Jul 2023 12:32:54 +0200</pubDate>
    </item>
    <item>
      <title>manpage fulltext search</title>
      <link>https://evilcookie.de/manpage-fulltext-search.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>manpage fulltext search</h1>

<p><code>man -K &lt;term&gt;</code> got you covered<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"> -K, --global-apropos
</span></span><span class="line"><span class="cl">        Search for text in all manual pages.  This is a brute-
</span></span><span class="line"><span class="cl">        force search, and is likely to take some time; if you can,
</span></span><span class="line"><span class="cl">        you should specify a section to reduce the number of pages
</span></span><span class="line"><span class="cl">        that need to be searched.  Search terms may be simple
</span></span><span class="line"><span class="cl">        strings (the default), or regular expressions if the
</span></span><span class="line"><span class="cl">        --regex option is used.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        Note that this searches the sources of the manual pages,
</span></span><span class="line"><span class="cl">        not the rendered text, and so may include false positives
</span></span><span class="line"><span class="cl">        due to things like comments in source files.  Searching
</span></span><span class="line"><span class="cl">        the rendered text would be much slower.
</span></span></code></pre>
<p>some useful additions:</p>

<ul>
<li><code>--regex</code>: search via regular expression</li>
<li><code>-P less</code>: use always a pager, otherwise short manpages will get printed without pager making it difficult to search within the page</li>
<li><code>--html=firefox</code>: show pages in the browser</li>
</ul>

<p>some interesting searches via <code>man -P less -K &lt;term&gt;</code>:</p>

<ul>
<li><code>knuth</code>, <code>torvalds</code>, <code>ritchie</code>: take some history lessons</li>
<li><code>&lt;swear&gt;</code>: look for your favorite swear</li>
<li><code>1337</code>: reveal the elite</li>
<li><code>coffee</code>: shows that one shouldn&rsquo;t use <a href="https://linux.die.net/man/1/espdiff"><code>espdiff</code></a> <em>&ldquo;while sleep-walking, or before your first cup of coffee&rdquo;</em></li>
<li><code>love</code>: who spreads the most love</li>
</ul>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">as I ran into the problem that I needed a fulltext serarch over man pages, my first thought was to set up an opensearch cluster feeding it with <code>man -a</code>&hellip;</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 07 Jul 2023 12:58:07 +0200</pubDate>
    </item>
    <item>
      <title>let&#39;s boot</title>
      <link>https://evilcookie.de/lets-boot.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>let&rsquo;s boot</h1>

<p>Let&rsquo;s boot some x86 code with qemu.</p>

<p>I rediscovered <a href="https://.osdev.org">osdev.org</a> after 13 years of abstinence<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup><sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> and started off with the plain-assembly <a href="https://wiki.osdev.org/Babystep1">babystep</a>. Then I tried the C based <a href="https://wiki.osdev.org/Bare_Bones">bare-bones</a> kernel to have a bit more convenience.</p>

<ul>
<li><a href="#minimal">Minimal working example</a></li>
<li><a href="#babystep">Babystep - plain assembler</a></li>
<li><a href="#barebones">Bare-Bones - C</a></li>
<li><a href="#findings">Findings</a>

<ul>
<li><a href="environment">Environment</a></li>
<li><a href="memory-layout"> Memory Layout</a></li>
</ul></li>
<li><a href="resources">Resources</a></li>
<li><a href="vision">Vision</a></li>
</ul>

<h2>Minimal working example<a id="minimal"/></h2>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="err">[</span><span class="nf">ORG</span> <span class="mi">0x7c00</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nl">hang:</span>
</span></span><span class="line"><span class="cl">    <span class="nf">jmp</span> <span class="no">hang</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">times</span> <span class="mi">510</span><span class="p">-(</span><span class="no">$-$$</span><span class="p">)</span> <span class="no">db</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="nf">db</span> <span class="mi">0x55</span>
</span></span><span class="line"><span class="cl"><span class="nf">db</span> <span class="mi">0xAA</span>
</span></span></code></pre>
<p>This <a href="https://nasm.us/">nasm</a> code is all you need to make an infinite blinking cursor:</p>

<p><img src="lets-boot_minimal_valid.gif"/></p>

<p>What is going on?</p>

<ul>
<li><code>[ORG 0x7c00]</code>: select the right sector, where <a href="https://github.com/qemu/seabios/blob/master/src/boot.c#L881">the bios expects the bootloader</a></li>
<li><code>hang: jmp hang</code>: plain assembly instructing the CPU to infinitely loop by jumping to the jump instruction</li>
<li><code>times 510-($-$$) db 0</code>: Bootloader needs to be exactly 512 bytes large in size. This pads the bootloader up with zeroes.

<ul>
<li>pad 510 bytes instead of 512 to leave two bytes free for the magic number</li>
<li><code>$-$$</code> is a macro calculating <code>&lt;end of file&gt; - &lt;start of file&gt;</code> resulting in the size of the bootloader so far</li>
<li><code>db 0</code> is just a static byte set to zero</li>
</ul></li>
<li><code>0x55aa</code> is the magic number to <a href="https://github.com/qemu/seabios/blob/master/src/boot.c#L901">tell the bios that this is a valid bootloader</a></li>
</ul>

<h2>Babystep - plain assembler<a id="babystep"/></h2>

<p>After the minimal working example, I approached the plain-assembler <a href="https://github.com/RaphaelPour/letsboot/tree/main/tutorials/babystep">babystep bootloader</a>, to get a better insight what&rsquo;s going on:</p>

<p>Learnings:</p>

<ul>
<li>basic memory alignment</li>
<li>enter protected mode: <a href="">code</a> <a href="">tutorial</a></li>
<li>write to console without interrupt: <a href="https://github.com/RaphaelPour/letsboot/blob/main/tutorials/babystep/boot3.asm#L86">code</a> <a href="">tutorial</a></li>
</ul>

<h2>Bare-Bones - C<a id="barebones"/></h2>

<p>It might be asked much operating at such a low level, but some convenience would be nice. C got you covered! At least a bit. The <a href="https://github.com/RaphaelPour/letsboot/tree/main/tutorials/bare-bones">bare-bones bootloader</a> contains has only as much assembler as necessary to load up C. Basically a stack must be allocated and <a href="https://github.com/RaphaelPour/letsboot/blob/main/tutorials/bare-bones/kernel.c">here we go</a>.</p>

<p>Learnings:</p>

<ul>
<li>bridge between assembler and C</li>
<li>more sophisticated tty</li>
</ul>

<h2>Findings<a id="findings"/></h2>

<h3>Environment<a id="environment"/></h3>

<p>Bootloaders aren&rsquo;t just usual<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup> assembler codes in a hosted environment where an OS is providing all kinds of neat stuff like a libc.
There is no such thing as <a href="https://www.man7.org/linux/man-pages/man5/elf.5.html">ELF</a> or <a href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format">PE</a>, just the bare-metal CPU which we must satisfy. This not only includes valid assembler code but stuff like:</p>

<ul>
<li>width: 8, 16 or 32 bit instruction width?</li>
<li>location: where needs the code to be placed to in order to get (not) executed. The cpu originally doesn&rsquo;t care whats data and code, it just jumps to a defined
address and interprets the corresponding bytes as instruction.</li>
</ul>

<h3>Memory Layout<a id="memory-layout"/></h3>

<p>In my understanding the assembler file not just contains code and needs to be aligned but is also almost the equivalent of the program that is actual in memory.
And because of this, some preprocessor stuff like <code>times 510-($-$$) db 0</code> has to be made at the end in order it is correctly loaded into the memory.</p>

<p>While researching online about x86 bootloader, two approaches emerged:</p>

<ul>
<li>manual alignment of the sections via labels, jumps</li>
<li>linker config with map which section goes where</li>
</ul>

<p>It looks like the later approach is mostly used for serious projects, where the former is just a quick n dirty workaround.</p>

<h2>Resources<a id="resources"/></h2>

<p>Additionally to <a href="https://wiki.osdev.org">osdev.org</a>, I also found a bunch of other interesting resources along the way.</p>

<p>General:</p>

<ul>
<li><a href="https://wiki.osdev.org/CPU_Registers_x86">Overview about the cpu registers</a></li>
<li><a href="https://en.wikipedia.org/wiki/BIOS_interrupt_call#Interrupt_table">BIOS interrupt table</a></li>
<li><a href="https://en.wikipedia.org/wiki/X86_instruction_listings">x86 instruction set</a></li>
<li><a href="https://www.felixcloutier.com/x86/index.html">Instructions</a></li>
</ul>

<p>Tutorials:</p>

<ul>
<li><a href="https://wiki.osdev.org/Babystep1">Babystep tutorial with pure assembler</a></li>
<li><a href="https://github.com/tanmayv25/x86-bootloader/tree/master">Example bootloader into c</a></li>
<li><a href="http://3zanders.co.uk/2017/10/13/writing-a-bootloader/">Bootloader tutorial</a></li>
<li><a href="https://cs.lmu.edu/~ray/notes/nasmtutorial/">NASM Tutorial</a></li>
<li><a href="https://blog.stefan-koch.name/2013/11/09/der-hello-world-bootloader">German tutorial</a></li>
</ul>

<p>Special:</p>

<ul>
<li><a href="https://0xax.gitbooks.io/linux-insides/content/">Linux inside handbook</a></li>
<li><a href="https://elixir.bootlin.com/linux/0.01/source">first linux</a></li>
<li><a href="https://review.coreboot.org/plugins/gitiles/seabios/+/refs/heads/master/src/x86.h">seabios boot</a> which qemu uses per default for booting</li>
</ul>

<h2>Vision<a id="vision"/></h2>

<ul>
<li>practice assembly using <a href="https://exercism.org/tracks/x86-64-assembly">exercism</a></li>
<li>implement a basic shell as entry point for various sub programs</li>
</ul>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Credits to <a href="https://github.com/Manawyrm">Manawyrm</a> for the inspiration</li>

<li id="fn:2">I already <a href="https://www.tutorials.de/resources/ein-eigenes-kleines-betriebssystem.84/">tossed some bits</a> (sorry, german only) 13 years ago but I felt too gatekept and didn&rsquo;t knew linux.</li>

<li id="fn:3">I couldn&rsquo;t write that without a laugh. As there would be something like usual assembler&hellip;</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 12 Jun 2023 12:29:46 +0200</pubDate>
    </item>
    <item>
      <title>Godot Wild Jam 55</title>
      <link>https://evilcookie.de/godot-wild-jam-55.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Godot Wild Jam 55 - zzZ</h1>

<p><img src="godot-wild-jam-55_zzz_intro.png"/></p>

<p>I did my first solo submission at the <a href="https://itch.io/jam/godot-wild-jam-55">godot wild jam 55</a> about the theme <em>dreams</em> and reached rank 29!
It&rsquo;s called <a href="https://itch.io/jam/godot-wild-jam-55/rate/1976329">zzZ</a> where the player catches sheep <em>to catch some z&rsquo;s</em><sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>.</p>

<p>Some more facts:</p>

<ul>
<li><a href="https://itch.io/jam/godot-wild-jam-55/rate/1976329">jam submission</a></li>
<li><a href="https://evilc00kie.itch.io/zzz">game</a></li>
<li><a href="https://github.com/Glow-Project/gwj-55">source code</a></li>
<li>two wildcards implemented:

<ul>
<li><em>A fork in the road</em>: four endings</li>
<li><em>Kabom!</em>: missed sheep explode</li>
</ul></li>
</ul>

<h3>Contents</h3>

<ul>
<li><a href="#idea">Idea</a></li>
<li><a href="#mechanics">Mechanics</a>

<ul>
<li><a href="#sheep spawner">Sheep spawner</a></li>
<li><a href="#basket">Basket</a></li>
<li><a href="#sunclock">Sunclock</a></li>
<li><a href="#tacho">Tacho (speedometer)</a></li>
<li><a href="#game-loop">Game loop</a></li>
<li><a href="#instantiated-scenes">Instantiated scenes</a></li>
</ul></li>
<li><a href="#audio">Audio</a>

<ul>
<li><a href="#background-music">Background music</a></li>
<li><a href="#audio-sheep">Sheep</a></li>
<li><a href="#music-box">Music box - intro + dreaming-end sound</a></li>
</ul></li>
<li><a href="#summary">Summary</a></li>
</ul>

<h2>Idea<a name='idea'/></h2>

<p><a href="https://github.com/Tch1b0">Johannes</a> had the idea of <em>falling sheeps that must get catched</em> but &ldquo;gifted&rdquo; it to me, since he couldn&rsquo;t do it himself due to lack of time.
The core mechanic was quite simple, but still fun to play for a few minutes. I was not hyped about it and that was actually my jam driver:</p>

<ul>
<li>simplicity: implement solid game mechanic with low innovation which makes it easy to <a href="https://idioms.thefreedictionary.com/kills+your+darlings"><em>kill my darlings</em></a>.</li>
<li>full stack: instead of delegating tasks/picking the ones I&rsquo;m good at, everything must be concepted and implemented by myself</li>
<li>own assets:

<ul>
<li>mspaint graphic: simple, sketchy, bare minimum that just works</li>
<li>ableton/dawless audio: game jams are a good opportunity to get passive feedback about my side quest &lsquo;music production&rsquo;</li>
</ul></li>
<li>focus within godot: <em>Does it add value to the player?</em>, avoid early optimization/polishing</li>
</ul>

<h2>Mechanics<a name='mechanics'/></h2>

<h3>Sheep spawner<a name='sheep spawner'/></h3>

<p><a href="https://github.com/Glow-Project/gwj-55/blob/main/sheep.gd">Sheep</a> are the essential entity of the game. They fall from the sky into the abyss unless the player catches them with the basket.</p>

<p><img src="godot-wild-jam-55_sheep.png"/></p>

<p><a href="https://github.com/Glow-Project/gwj-55/blob/main/spawner.gd">The spawner</a> is a scene on its own deciding where and when to generate sheep such as registering the abyss event, that a sheep emits once it fell into the abyss. To know where the abyss is, the spawner awaits the position of it.
Sheep get spawned once a second with random size, initial speed and position For choosing a random position, the spawner awaits another two points aka <code>Marker2D</code>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nd">@export</span> <span class="n">var</span> <span class="n">left_point</span><span class="p">:</span><span class="n">Marker2D</span>
</span></span><span class="line"><span class="cl"><span class="nd">@export</span> <span class="n">var</span> <span class="n">right_point</span><span class="p">:</span><span class="n">Marker2D</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="n">_on_timer_timeout</span><span class="p">(</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="n">var</span> <span class="n">sheep</span><span class="p">:</span><span class="n">Sheep</span> <span class="o">=</span> <span class="n">sheep_scene</span><span class="o">.</span><span class="n">instantiate</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="c1"># ...some more initalization...</span>
</span></span><span class="line"><span class="cl">	<span class="n">sheep</span><span class="o">.</span><span class="n">global_position</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">randf_range</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">		<span class="n">left_point</span><span class="o">.</span><span class="n">global_position</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">		<span class="n">right_point</span><span class="o">.</span><span class="n">global_position</span><span class="o">.</span><span class="n">x</span>
</span></span><span class="line"><span class="cl">		<span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="n">sheep</span><span class="o">.</span><span class="n">global_position</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">left_point</span><span class="o">.</span><span class="n">position</span><span class="o">.</span><span class="n">y</span>
</span></span></code></pre>
<p>Those points are visually placed above the game scene:</p>

<p><img src="godot-wild-jam-55_spawner.png"/></p>

<p>About every 10th sheep is special having one of the three complement colors cyan, magenta or yellow such as a smaller random size and a higher random initial speed. They&rsquo;re worth double on collecting and triple on not collecting them.</p>

<h3>Basket<a name='basket'/></h3>

<p><a href="https://github.com/Glow-Project/gwj-55/blob/main/basket.gd">The basket</a> emits an event for every sheep it collides with. Godot 4 makes it easy to automate collision shape generation from a sprite with complex shape:</p>

<p><img src="godot-wild-jam-55_basket.png"/></p>

<p>The basket&rsquo;s x-axis can be controlled via mouse which is hidden (via <a href="https://github.com/Glow-Project/gwj-55/blob/main/game.gd">game scene&rsquo;s</a> <code>Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)</code>):</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">extends</span> <span class="n">Area2D</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">signal</span> <span class="n">item_collected</span><span class="p">(</span><span class="n">body</span><span class="p">:</span><span class="n">Node2D</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="n">_input</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="o">-</span><span class="o">&gt;</span> <span class="n">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="n">event</span> <span class="ow">is</span> <span class="n">InputEventMouseMotion</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="n">global_position</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">position</span><span class="o">.</span><span class="n">x</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="n">_on_body_entered</span><span class="p">(</span><span class="n">body</span><span class="p">)</span> <span class="o">-</span><span class="o">&gt;</span> <span class="n">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="n">emit_signal</span><span class="p">(</span><span class="sa"></span><span class="s2">&#34;</span><span class="s2">item_collected</span><span class="s2">&#34;</span><span class="p">,</span> <span class="n">body</span><span class="p">)</span>
</span></span></code></pre>
<h3>Sunclock<a name='sunclock'/></h3>

<p><a href="https://github.com/Glow-Project/gwj-55/blob/main/sunclock.gd">The sunclock</a> is the timer of the game, visually similar to the one in <a href="https://minecraft.fandom.com/wiki/Clock">minecraft</a>. It consists of two
sprite layers. The bottom &ldquo;clock&rdquo;-layer gets rotated one revolution in a specified amount of time.</p>

<p><img src="godot-wild-jam-55_sunclock.png"/></p>

<p>This can be implemented via tween:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">extends</span> <span class="n">Node2D</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">signal</span> <span class="n">sunrise</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@export</span> <span class="n">var</span> <span class="n">duration</span><span class="p">:</span><span class="nb">int</span> <span class="o">=</span> <span class="mi">30</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="n">_ready</span><span class="p">(</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="n">var</span> <span class="n">tween</span> <span class="o">=</span> <span class="n">create_tween</span><span class="p">(</span><span class="p">)</span><span class="o">.</span><span class="n">set_parallel</span><span class="p">(</span><span class="n">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="n">tween</span><span class="o">.</span><span class="n">tween_property</span><span class="p">(</span><span class="err">$</span><span class="n">Clock</span><span class="p">,</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">rotation_degrees</span><span class="s2">&#34;</span><span class="p">,</span> <span class="mi">180</span><span class="p">,</span> <span class="n">duration</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="n">tween</span><span class="o">.</span><span class="n">tween_property</span><span class="p">(</span><span class="err">$</span><span class="n">ClockSound</span><span class="p">,</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">volume_db</span><span class="s2">&#34;</span><span class="p">,</span> <span class="o">-</span><span class="mi">10</span><span class="p">,</span> <span class="n">duration</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">await</span> <span class="n">tween</span><span class="o">.</span><span class="n">finished</span>
</span></span><span class="line"><span class="cl">	<span class="n">emit_signal</span><span class="p">(</span><span class="sa"></span><span class="s2">&#34;</span><span class="s2">sunrise</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span></code></pre>
<ul>
<li><code>set_parallel(true)</code> is needed, so multiple properties can be controlled with the same tween simultaneously</li>
<li>Additionally a ticking clock gets louder the more the clock approaches the end/next morning. Since the tween increases volume linearly but dB is logarithmic, the sound is barely hearable until the last few seconds, which is a nice side effect.</li>
<li><code>await tween.finished</code> is <a href="https://github.com/godotengine/godot/pull/41794">new in Godot 4</a> and replaces the <code>yield</code></li>
<li>the sunrise event gets emitted after the tween is finished/the time is over</li>
</ul>

<h3>Tacho (speedometer)<a name='tacho'/></h3>

<p><a href="https://github.com/Glow-Project/gwj-55/blob/main/tacho.gd">The tacho</a> shows a half circle on which a needle indicates the state of sleepiness:</p>

<ul>
<li>left: fully awake, emit event</li>
<li>middle: half asleep, game starts there</li>
<li>right: fully asleep, emit event</li>
</ul>

<p>There are three animated faces that should transport the meaning of the tacho:</p>

<p><img src="godot-wild-jam-55_face.png"/></p>

<p>The score is spread evenly across the 180° range. The code is quite messy but I don&rsquo;t want to hide anything:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">extends</span> <span class="n">Node2D</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">signal</span> <span class="n">fallen_asleep</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">signal</span> <span class="n">woken_up</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@export</span> <span class="n">var</span> <span class="n">total</span><span class="p">:</span><span class="nb">int</span> <span class="o">=</span> <span class="mi">30</span>
</span></span><span class="line"><span class="cl"><span class="nd">@onready</span> <span class="n">var</span> <span class="n">score</span><span class="p">:</span><span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">var</span> <span class="n">event_emitted</span><span class="p">:</span><span class="nb">bool</span> <span class="o">=</span> <span class="n">false</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="n">_ready</span><span class="p">(</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="err">$</span><span class="n">Emoji</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="sa"></span><span class="s2">&#34;</span><span class="s2">half_sleeping</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Called every frame. &#39;delta&#39; is the elapsed time since the previous frame.</span>
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="n">_process</span><span class="p">(</span><span class="n">delta</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="err">$</span><span class="n">Needle</span><span class="o">.</span><span class="n">global_rotation_degrees</span> <span class="o">=</span> <span class="n">clamp</span><span class="p">(</span><span class="mi">180</span><span class="o">/</span><span class="n">total</span><span class="o">*</span><span class="n">score</span> <span class="o">+</span> <span class="mf">90.0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">180</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="n">var</span> <span class="n">animation</span> <span class="o">=</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">half_sleeping</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="n">score</span> <span class="o">&gt;</span><span class="o">=</span> <span class="n">total</span><span class="o">/</span><span class="mi">4</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="n">animation</span> <span class="o">=</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">asleep</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="k">elif</span> <span class="n">score</span> <span class="o">&lt;</span><span class="o">=</span> <span class="o">-</span><span class="n">total</span><span class="o">/</span><span class="mi">4</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="n">animation</span> <span class="o">=</span> <span class="sa"></span><span class="s2">&#34;</span><span class="s2">awake</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="err">$</span><span class="n">Emoji</span><span class="o">.</span><span class="n">animation</span> <span class="o">!=</span> <span class="n">animation</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="err">$</span><span class="n">Emoji</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="n">animation</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="n">inc</span><span class="p">(</span><span class="n">val</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span><span class="o">-</span><span class="o">&gt;</span><span class="n">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="n">score</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">score</span><span class="o">+</span><span class="n">val</span><span class="p">,</span> <span class="n">total</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="n">score</span> <span class="o">==</span> <span class="n">total</span> <span class="ow">and</span> <span class="err">!</span><span class="n">event_emitted</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="n">emit_signal</span><span class="p">(</span><span class="sa"></span><span class="s2">&#34;</span><span class="s2">fallen_asleep</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="n">event_emitted</span> <span class="o">=</span> <span class="n">true</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">func</span> <span class="n">dec</span><span class="p">(</span><span class="n">val</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span><span class="o">-</span><span class="o">&gt;</span><span class="n">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="n">score</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">score</span><span class="o">-</span><span class="n">val</span><span class="p">,</span> <span class="o">-</span><span class="n">total</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="n">score</span> <span class="o">==</span> <span class="n">total</span> <span class="ow">and</span> <span class="err">!</span><span class="n">event_emitted</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="n">emit_signal</span><span class="p">(</span><span class="sa"></span><span class="s2">&#34;</span><span class="s2">woken_up</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="n">event_emitted</span> <span class="o">=</span> <span class="n">true</span>
</span></span></code></pre>
<p><code>event_emitted</code> debounces the event, so it gets only emitted once even if the player collectes more sheeps while the event wasn&rsquo;t consumed quickly enough by the game scene.</p>

<h3>Game loop<a name='game-loop'/></h3>

<p><a href="https://github.com/Glow-Project/gwj-55/blob/main/game.gd">The game scene</a> holds everything together while only waiting for three different events:</p>

<ul>
<li>sheep got collected: increment tacho, play sheep sound, free sheep node</li>
<li>sheep felt into the byss: decrement tacho, play explosion animation+sound, free sheep node</li>
<li>timer is over/ sunrise emitted by sunclock: change to game over scene</li>
</ul>

<p>All three events check if an end has been reached and if so, set the globals correctly, make the mouse visible again and change to the game over scene.
This is where the wildcard <em>A fork in the road</em> is implemented. Additionally the timeout event can decide between two ends depending if the player is more awake (score is negative, needle is on the left) or more sleepy (score is positive, needle is on the right or in the middle).</p>

<p>Retrospectively looking at the code: There is too much responsibility shared between game&lt;-&gt;tacho and game&lt;-&gt;game over. If I&rsquo;d invest more time into the game, I&rsquo;d refactor this inconsistency. The game itself shouldn&rsquo;t need to provide any content to game over. Also the game shouldn&rsquo;t need to know how to use the tacho&rsquo;s score for deciding if and which end has been reached.</p>

<h3>Intro<a name='intro'/></h3>

<p><a href="https://github.com/Glow-Project/gwj-55/blob/main/intro.gd">The intro</a> is basically an animation player blending in all the logos synced with the music box. In order to make the synchronization more reliable, the three main parts of the intro sound are split and played after each other. In theory, if the CPU is too slow, the break between the notes are higher, but that is totally fine.</p>

<p><img src="godot-wild-jam-55_intro_animation.png"/></p>

<h3>Godot - instantiated scenes<a name='instantiated-scenes'/></h3>

<p>In some cases it might be handy to change to a scene with some context. E.g. tell the game over screen which end has been reached. Sadly I couldn&rsquo;t find an idiomatic solution to create such instantiated scenes. If you instantiate a scene with parameters, you can&rsquo;t change to it. It is only possible to add it as a child or <a href="https://godotengine.org/qa/24773/how-to-load-and-change-scenes">use a hacky alternative</a>.</p>

<p>I added a plain auto load script <code>Globals.gd</code> and stored the state there. I dislike this approach while everyone could read/write the state.</p>

<h2>Audio<a name='audio'/></h2>

<p>Since my <a href="https://soundcloud.com/noise-taeter">alter ego</a> loves to produce and play around with audio, I couldn&rsquo;t resist to invest some time into music and sound effect production.</p>

<h3>Background music<a name='background-music'/></h3>

<p>Describing the creative process of making music isn&rsquo;t that reasonable than e.g. programming where the problem-solution relation can be argued quite rational.
I&rsquo;ll try to describe it either way.</p>

<p>The first auditive association of dreamy game music for me was the <a href="https://www.youtube.com/watch?v=RRfHbyCQDCo">Super Mario 64 Dire Dire Docks theme</a>.
Old consoles often use <a href="https://www.youtube.com/watch?v=vvBl3YUBUyY">FM synthesis</a> to generate complex instruments with a low memory footprint<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>. I decided to just play around with some c major chords (because this scale is the easiest one to play), with my dawless<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup> setup consisting of a MIDI Keyboard connected to the Korg FM2 which gets recorded by my digital recorder. The FM8 comes close to the Nintendo64 music engine while it also implements fm synthesis. I pressed record and played around with some chords and presets. I layered two chord progression takes but unfortunately haven&rsquo;t saved the project file&hellip; So the first layer is the first and loud chord progression and the second layer is the more quite progression that can be heard in between to given some kind of &ldquo;response&rdquo; if the first layer gave a &ldquo;call&rdquo;.</p>

<p><img src="godot-wild-jam-55_dawless.png"/></p>

<h3>Sheep<a name='audio-sheep'/></h3>

<p>I sliced a few different sheep sounds from <a href="https://freesound.org/people/milkotz/sounds/618865/">milkotz&rsquo;s recording</a> and pre loaded them, so playing them back has a low latency:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">var</span> <span class="n">sheeps</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">	<span class="n">preload</span><span class="p">(</span><span class="sa"></span><span class="s2">&#34;</span><span class="s2">res://milkotz_sheep1.mp3</span><span class="s2">&#34;</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="n">preload</span><span class="p">(</span><span class="sa"></span><span class="s2">&#34;</span><span class="s2">res://milkotz_sheep2.mp3</span><span class="s2">&#34;</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="n">preload</span><span class="p">(</span><span class="sa"></span><span class="s2">&#34;</span><span class="s2">res://milkotz_sheep3.mp3</span><span class="s2">&#34;</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="n">preload</span><span class="p">(</span><span class="sa"></span><span class="s2">&#34;</span><span class="s2">res://milkotz_sheep4.mp3</span><span class="s2">&#34;</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span></code></pre>
<p>Since there are small and big sheep, why not pitching the sample in relation to the size? Quickly a formula <code>pitch = 1 - (size-0.9)</code> was crafted with educated guessing such as trial-and-error. The pitch&rsquo;s default is set to 1. Basically it maps the range of the sheep scale factor within the range <code>[0.1,1]</code><sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup> onto the pitch range <code>[0.9, 1.8]</code> in reverse, because smaller sheep have higher pitches and vice versa. This means the smallest sheep with a size of <code>0.1</code> has a pitch of <code>1-(0.1-0.9) = 1.8</code> where the biggest sheep has a pitch of <code>1-(1-0.9) = 0.9</code><sup class="footnote-ref" id="fnref:5"><a href="#fn:5">5</a></sup>.</p>

<p>To have limitless parallel sheep sounds, an audio player get initialized for each collected sheep:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">func</span> <span class="n">_on_basket_item_collected</span><span class="p">(</span><span class="n">body</span><span class="p">:</span><span class="n">Sheep</span><span class="p">)</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="n">var</span> <span class="n">sheep_player</span> <span class="o">=</span> <span class="n">AudioStreamPlayer</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="n">sheep_player</span><span class="o">.</span><span class="n">stream</span> <span class="o">=</span> <span class="n">sheeps</span><span class="p">[</span><span class="n">randi_range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="nb">len</span><span class="p">(</span><span class="n">sheeps</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">	<span class="n">sheep_player</span><span class="o">.</span><span class="n">set_bus</span><span class="p">(</span><span class="sa"></span><span class="s2">&#34;</span><span class="s2">SheepFX</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="n">sheep_player</span><span class="o">.</span><span class="n">pitch_scale</span> <span class="o">-</span><span class="o">=</span> <span class="p">(</span><span class="n">body</span><span class="o">.</span><span class="n">size</span><span class="o">-</span><span class="mf">0.9</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="n">add_child</span><span class="p">(</span><span class="n">sheep_player</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="n">sheep_player</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="p">)</span>
</span></span></code></pre>
<h3>Music box - intro + dreaming-end sound<a name='music-box'/></h3>

<p>The intro such as the dreaming-end have a music box to add a bit coziness/sleepiness to the scene.</p>

<h4>Instrument</h4>

<p>The instrument was made with a preset such as a few effects:</p>

<p><img src="godot-wild-jam-55_musicbox_effect_chain.png"/></p>

<ul>
<li><a href="https://www.ableton.com/en/packs/collision/">Ableton&rsquo;s Collision</a> with preset &ldquo;Glockenspiel basic&rdquo;: a typical music box sound but a bit to high</li>
<li>Chorus: Add more vibrato/pitch modulation to sound more natural.</li>
<li>Cabinet: Dampen the sound to make it more like it was recorded in a room.</li>
<li>EQ:

<ul>
<li>Cut off the lows is always good if they&rsquo;re not needed to avoid dirty mixes/rumbling sound.</li>
<li>Make the highs a bit more quiet additionally to the cabinet.</li>
</ul></li>
<li>Compressor: Nothing special, just make the sound more louder. This may be obsolete since I export all my samples normalized.</li>
</ul>

<h4>Notes</h4>

<p>Although the <a href="https://www.youtube.com/watch?v=dRw8Z32ECKo">whole-tone-scale</a> is usually used for dream sequences, I wanted something more naive and chose the c major scale again.
I tried to mimic the &ldquo;ascending stairs&rdquo; music box melodies often have and added a little offset to some notes so it sounds more analog.</p>

<p>Intro notes:
<img src="godot-wild-jam-55_musicbox_notes_intro.png"/></p>

<p>Dreaming-end notes:
<img src="godot-wild-jam-55_musicbox_notes_dreaming.png"/></p>

<h2>Summary<a name='summary'/></h2>

<p>The initial driver remained throughout the week and I learned some new things about Godot 4. Each mechanic could be outsourced to its own independent scene and connected to each other via events, eliminating a classical game loop.</p>

<p>Although everything works pretty bug free, the game scene holds more state than it should making it&rsquo;s role inconsistent in relation to tacho and game over. I&rsquo;d refactor this one if I&rsquo;d invest more time into this game.</p>

<p>Keeping the graphics simple and just sketch them via mspaint within only a few minuted helped to focus on the overall progress in contrast to the other jams.</p>

<p>The submission took the 29th place:</p>

<p><img src="godot-wild-jam-55_ranking.png"/></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Thanks to <a href="https://itch.io/post/7510574">FGKeiji&rsquo;s comment</a> to teach me this phrase!</li>

<li id="fn:2">A preset can be described by a few coefficients along with the used algorithm.</li>

<li id="fn:3">No &lsquo;Digital Audio Workstation&rsquo; which is often helpful on focusing since it isn&rsquo;t flooded with features and possibilities.</li>

<li id="fn:4">The minimum and maximum of all random sizes define the absolute range of all possible sizes: <a href="https://github.com/Glow-Project/gwj-55/blob/main/sheep.gd#L25">https://github.com/Glow-Project/gwj-55/blob/main/sheep.gd#L25</a></li>

<li id="fn:5">You&rsquo;re jamming on your keyboard <em>&ldquo;I know easier approaches!&rdquo;</em>? -&gt; teachme@evilcookie.de</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Sat, 25 Mar 2023 18:55:30 +0100</pubDate>
    </item>
    <item>
      <title>Blogstage-static web server in rust</title>
      <link>https://evilcookie.de/blogstage-static-web-server-in-rust.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>blogstage - static web server in rust</h1>

<p><img src="blogstage-static-web-server-in-rust_blogstage_left_the_port.jpg"/></p>

<p>I was looking for a useful service-oriented Rust project where I can test my project standards<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> and dive deeper into the language.
I decided to replace the &ldquo;caddy file server&rdquo; that serves this blog. The result is called <a href="https://github.com/RaphaelPour/blogstage">blogstage</a>: <em>Simple web server providing my static blog to the world.</em></p>

<p>It can be used via <code>blogstage &lt;ip:port&gt; &lt;path&gt;</code> or just <code>blogstage 0.0.0.0:80 ./blog/</code>.</p>

<h3>Contents</h3>

<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#how-to-serve">How to serve</a>

<ul>
<li><a href="#argument-parser">Argument parser</a></li>
<li><a href="#file-cache">File cache</a><br>
</li>
<li><a href="#tcp">TCP</a></li>
<li><a href="#http">HTTP</a></li>
<li><a href="#parallel-request-handling">Parallel request handling</a></li>
<li><a href="#exit">Exit</a></li>
</ul></li>
<li><a href="#testing">Testing</a>

<ul>
<li><a href="#unit-test">Unit test</a></li>
<li><a href="#integration-test">Integration test</a></li>
</ul></li>
<li><a href="#benchmark">Benchmark</a></li>
<li><a href="#wrap-it-up">Wrap it up</a></li>
<li><a href="#vision">Vision</a></li>
</ul>

<h2>Requirements<a name="requirements"></h2>

<p>The requirements were fairly simple, because the blog is static consisting of a flat directory of rendered HTML files along with some images<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> and my
reverse-proxy is handling the TLS stuff:</p>

<ul>
<li>bind to given address+port</li>
<li>serve files from given directory (and prevent serving other directories e.g. via relative paths)</li>
<li>serve text and binary for HTML and images</li>
<li>not too easy to <em>dive deeper into rust</em></li>
</ul>

<h2>How to serve<a name="how-to-serve"></h2>

<p>Since the requirements weren&rsquo;t hard to fulfill, there are <a href="https://lib.rs/web-programming/http-server">tons of crates</a> that
can do the job. E.g. <a href="https://docs.rs/warp/0.3.3/warp/">warp</a> can do it in one line with something like <code>warp::serve(warp::fs::dir(&quot;./blog&quot;)).run(([127, 0, 0, 1], 8080))</code>. I decided against a ready-to-use crate, to make it a bit more difficult and educational.</p>

<p><a href="https://docs.rs/web_server/0.4.2/web_server">web_server</a> didn&rsquo;t worked with dynamic strings, since <a href="https://docs.rs/web_server/latest/web_server/struct.HttpServer.html#method.get">routes need to be added</a> with <code>&amp;'static str</code> where I couldn&rsquo;t figure out if and how this can be fixed<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>.</p>

<p>The solution was surprisingly easy to find. There is a tutorial about <a href="https://doc.rust-lang.org/book/ch20-00-final-project-a-web-server.html">Building a Multithreaded Web Server</a> in the official rust docs. What a coincidence!</p>

<h3>Argument parser<a name="argument-parser"></h3>

<p>Just two mandatory positional arguments without a default to keep things simple and explicit:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cm">/*</span><span class="cm"> parse arguments </span><span class="cm">*/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">let</span><span class="w"> </span><span class="n">uri</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">std</span>::<span class="n">env</span>::<span class="n">args</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">nth</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">Some</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">uri</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">None</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;usage: blogstage &lt;URI&gt; &lt;PATH&gt;&#34;</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="k">return</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">let</span><span class="w"> </span><span class="n">path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">std</span>::<span class="n">env</span>::<span class="n">args</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">nth</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">Some</span><span class="p">(</span><span class="n">path</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">path</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">None</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;usage: blogstage &lt;URI&gt; &lt;PATH&gt;&#34;</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="k">return</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span></code></pre>
<h3>File cache<a name="file-cache"></h3>

<p>The blog is pretty small, and its container<sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup> gets rebuilt for any change. Therefore I decided to load
all the files non-recursively into a hash map with with <a href="https://en.wikipedia.org/wiki/Basename">basename</a>
as key and content as value.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cm">/*</span><span class="cm"> load files </span><span class="cm">*/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">let</span><span class="w"> </span><span class="n">raw_entries</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">fs</span>::<span class="n">read_dir</span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="n">entries</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">entries</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;error reading files from {}: {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">path</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="k">return</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">files</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">for</span><span class="w"> </span><span class="n">entry</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">raw_entries</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="o">!</span><span class="n">entry</span><span class="p">.</span><span class="n">as_ref</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">path</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">is_file</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="k">continue</span><span class="w"></span><span class="nl"></span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">files</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="n">entry</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="p">.</span><span class="n">as_ref</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="p">.</span><span class="n">file_name</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="p">.</span><span class="n">into_string</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="n">fs</span>::<span class="n">read</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">as_ref</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">path</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<h3>TCP<a name="tcp"></h3>

<p>Although doing TCP by myself felt a bit too low-level in the first place, it was quite pleasant with rust using only <code>bind</code> and an <code>incoming</code> iterator:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cm">/*</span><span class="cm"> start server </span><span class="cm">*/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">let</span><span class="w"> </span><span class="n">listener</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">TcpListener</span>::<span class="n">bind</span><span class="p">(</span><span class="n">uri</span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="cm">/*</span><span class="cm"> error handling </span><span class="cm">*/</span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">for</span><span class="w"> </span><span class="n">stream</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">listener</span><span class="p">.</span><span class="n">incoming</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">match</span><span class="w"> </span><span class="n">stream</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">on_request</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span><span class="w"> </span><span class="n">fileHashMap</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="cm">/*</span><span class="cm"> error handling </span><span class="cm">*/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<h3>HTTP<a name="http"></h3>

<p>The request handler has a TCP stream such as the hash map containing all the files:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">on_request</span><span class="p">(</span><span class="k">mut</span><span class="w"> </span><span class="n">stream</span>: <span class="nc">TCPStream</span><span class="p">,</span><span class="w"> </span><span class="n">files</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">u8</span><span class="o">&gt;</span><span class="o">&gt;</span><span class="p">)</span><span class="w">
</span></span></span></code></pre>
<p>Then the request will get read until an empty line has been reached:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="n">reader</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BufReader</span>::<span class="n">new</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="n">stream</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">let</span><span class="w"> </span><span class="n">request</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">_</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reader</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">.</span><span class="n">lines</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">result</span><span class="o">|</span><span class="w"> </span><span class="n">result</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">.</span><span class="n">take_while</span><span class="p">(</span><span class="o">|</span><span class="n">line</span><span class="o">|</span><span class="w"> </span><span class="o">!</span><span class="n">line</span><span class="p">.</span><span class="n">is_empty</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">.</span><span class="n">collect</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span></code></pre>
<p>Parse the requested file quick &lsquo;n&rsquo; dirty (see <a href="#vision">vision</a>). Additionally <code>index.html</code> if the requested filename is empty for convenience:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">target</span>: <span class="nb">String</span> <span class="o">=</span><span class="w"> </span><span class="n">request</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="sc">&#39; &#39;</span><span class="p">)</span><span class="p">.</span><span class="n">collect</span>::<span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="o">&amp;</span><span class="kt">str</span><span class="o">&gt;</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">[</span><span class="mi">1</span><span class="o">..</span><span class="p">]</span><span class="p">.</span><span class="n">to_string</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">if</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">is_empty</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">  </span><span class="n">target</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&#34;index.html&#34;</span><span class="p">.</span><span class="n">into</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<p>In order to serve more complex files like images (and to be future ready if I add openscad or mp3 stuff), guess the mime type
via the crate&hellip;well&hellip;<a href="https://docs.rs/mime_guess/latest/mime_guess/">mime_guess</a>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="n">mime</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mime_guess</span>::<span class="n">from_path</span><span class="p">(</span><span class="n">target</span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">.</span><span class="n">first</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span></code></pre>
<p>If the requested file can be found in the hashmap, write its content along with a valid HTTP header to the stream.
Otherwise just write a HTTP header with status code <a href="https://http.cat/404">404</a>.
On any error, the response handler panics caused by the massive use of <code>unwrap</code>, and the thread just vanishes into the void (see <a href="#vision">vision</a>):</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">match</span><span class="w"> </span><span class="n">files</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="o">&amp;</span><span class="n">target</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">  </span><span class="nb">Some</span><span class="p">(</span><span class="n">body</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">length</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">body</span><span class="p">.</span><span class="n">len</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;200 {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">target</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">stream</span><span class="p">.</span><span class="n">write_all</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">      </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;HTTP/1.1 200 OK\r\nContent-Length: {length}\r\nContent-Type: {mime}\r\n\r\n&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">      </span><span class="p">.</span><span class="n">as_bytes</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">stream</span><span class="p">.</span><span class="n">write_all</span><span class="p">(</span><span class="n">body</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">  </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">  </span><span class="nb">None</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;404 {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">target</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">stream</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">      </span><span class="p">.</span><span class="n">write_all</span><span class="p">(</span><span class="s">&#34;HTTP/1.1 404 NOT FOUND\r\n\r\n&#34;</span><span class="p">.</span><span class="n">as_bytes</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">      </span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">  </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span></code></pre>
<h3>Parallel request handling<a name="parallel-request-handling"></h3>

<p>Since I want to implement parallel request handling as simple as possible and don&rsquo;t need to limit the amount of requests<sup class="footnote-ref" id="fnref:5"><a href="#fn:5">5</a></sup>, <a href="https://doc.rust-lang.org/std/thread/"><code>thread::spawn</code></a> will do the trick:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">for</span><span class="w"> </span><span class="n">stream</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">listener</span><span class="p">.</span><span class="n">incoming</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">match</span><span class="w"> </span><span class="n">stream</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">files</span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">thread</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">|</span><span class="o">|</span><span class="w"> </span><span class="n">on_request</span><span class="p">(</span><span class="n">s</span><span class="p">,</span><span class="w"> </span><span class="n">f</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;error accepting connection: {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="k">continue</span><span class="w"></span><span class="nl"></span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<p>The file map must be cloned, so its ownership can be moved to the thread.</p>

<h3>Exit<a name="exit"></h3>

<p>It doesn&rsquo;t deserve the predicate <strong>graceful</strong>, but it provides some simple mechanism to simply abort the whole request handling via the crate <a href="https://docs.rs/ctrlc/3.1.9/ctrlc/">ctrlc</a>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">ctrlc</span>::<span class="n">set_handler</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">|</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">   </span><span class="n">std</span>::<span class="n">process</span>::<span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span></code></pre>
<h2>Testing<a name="testing"></h2>

<p>My testing goal was to cover the <code>on_request</code> method via unit- and the CLI via integration-tests.</p>

<h3>Unit test<a name="unit-test"></h3>

<p>To test the <code>on_request</code> method, the stream must be mocked. Looking closely what the function actually
does with the stream reveals that we actually only need to read from and write to it. <a href="https://rust-lang.github.io/async-book/09_example/03_tests.html#testing-the-tcp-server">As described in the tutorial</a>,
<code>TCPStream</code> can be replaced by allowing any type that implements the <code>Read</code> and <code>Write</code> trait using <code>impl Read+Write</code>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">on_request</span><span class="p">(</span><span class="k">mut</span><span class="w"> </span><span class="n">stream</span>: <span class="nc">impl</span><span class="w"> </span><span class="n">Read</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Write</span><span class="p">,</span><span class="w"> </span><span class="n">files</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">u8</span><span class="o">&gt;</span><span class="o">&gt;</span><span class="p">)</span><span class="w">
</span></span></span></code></pre>
<p>The mock implements all methods needed for properly read and write to it. I modified the tutorial&rsquo;s mock to be single-threaded as we don&rsquo;t use async:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">assert_cmd</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">predicates</span>::<span class="n">prelude</span>::<span class="o">*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">cmp</span>::<span class="n">min</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="p">{</span><span class="n">Read</span><span class="p">,</span><span class="w"> </span><span class="n">Write</span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">process</span>::<span class="n">Command</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">MockTcpStream</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">read_data</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">u8</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">write_data</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">u8</span><span class="o">&gt;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// https://doc.rust-lang.org/std/io/trait.Read.html
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">impl</span><span class="w"> </span><span class="n">Read</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">MockTcpStream</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="bp">Self</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="p">[</span><span class="kt">u8</span><span class="p">]</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">io</span>::<span class="nb">Result</span><span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">size</span>: <span class="kt">usize</span> <span class="o">=</span><span class="w"> </span><span class="n">min</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">read_data</span><span class="p">.</span><span class="n">len</span><span class="p">(</span><span class="p">)</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="p">.</span><span class="n">len</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="n">buf</span><span class="p">[</span><span class="o">..</span><span class="n">size</span><span class="p">]</span><span class="p">.</span><span class="n">copy_from_slice</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">.</span><span class="n">read_data</span><span class="p">[</span><span class="o">..</span><span class="n">size</span><span class="p">]</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">size</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// https://doc.rust-lang.org/std/io/trait.Write.html
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">impl</span><span class="w"> </span><span class="n">Write</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">MockTcpStream</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">write</span><span class="p">(</span><span class="bp">self</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="bp">Self</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span>: <span class="kp">&amp;</span><span class="p">[</span><span class="kt">u8</span><span class="p">]</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">io</span>::<span class="nb">Result</span><span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">write_data</span><span class="p">.</span><span class="n">extend</span><span class="p">(</span><span class="n">buf</span><span class="p">.</span><span class="n">iter</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">cloned</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">buf</span><span class="p">.</span><span class="n">len</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">fn</span> <span class="nf">flush</span><span class="p">(</span><span class="bp">self</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="bp">Self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">io</span>::<span class="nb">Result</span><span class="o">&lt;</span><span class="p">(</span><span class="p">)</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<p>Then tests can simply be written as such:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cp">#[</span><span class="cp">test</span><span class="cp">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">serve_not_found</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">input</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">b&#34;</span><span class="s">GET /test.html HTTP/1.1</span><span class="se">\r</span><span class="se">\n</span><span class="se">\r</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">contents</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="mi">0</span><span class="k">u8</span><span class="p">;</span><span class="w"> </span><span class="mi">1024</span><span class="p">]</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">contents</span><span class="p">[</span><span class="o">..</span><span class="n">input</span><span class="p">.</span><span class="n">len</span><span class="p">(</span><span class="p">)</span><span class="p">]</span><span class="p">.</span><span class="n">clone_from_slice</span><span class="p">(</span><span class="n">input</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">stream</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MockTcpStream</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="n">read_data</span>: <span class="nc">contents</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="n">write_data</span>: <span class="nb">Vec</span>::<span class="n">new</span><span class="p">(</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">files</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">blogstage</span>::<span class="n">on_request</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="n">stream</span><span class="p">,</span><span class="w"> </span><span class="n">files</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">expected_response</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;HTTP/1.1 404 NOT FOUND\r\n\r\n&#34;</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="fm">assert!</span><span class="p">(</span><span class="n">stream</span><span class="p">.</span><span class="n">write_data</span><span class="p">.</span><span class="n">starts_with</span><span class="p">(</span><span class="n">expected_response</span><span class="p">.</span><span class="n">as_bytes</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<h3>Integration test<a name="integration-test"></h3>

<p>Each integration test case ensures that the binary behaves correctly with respect to the given environment and arguments. The following test checks if <code>blogstage</code> fails correctly when provided with no arguments:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cp">#[</span><span class="cp">test</span><span class="cp">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">uri_is_missing</span><span class="p">(</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(</span><span class="p">)</span><span class="p">,</span><span class="w"> </span><span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span><span class="w"> </span><span class="n">std</span>::<span class="n">error</span>::<span class="n">Error</span><span class="o">&gt;</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">cmd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Command</span>::<span class="n">cargo_bin</span><span class="p">(</span><span class="s">&#34;blogstage&#34;</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">cmd</span><span class="p">.</span><span class="n">assert</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">.</span><span class="n">stdout</span><span class="p">(</span><span class="n">predicate</span>::<span class="kt">str</span>::<span class="n">contains</span><span class="p">(</span><span class="s">&#34;usage: blogstage &lt;URI&gt; &lt;PATH&gt;\n&#34;</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<ul>
<li>cases are based on the clip application test section from <a href="https://rust-cli.github.io/book/tutorial/testing.html#testing-cli-applications-by-running-them">the official docs</a></li>
<li>execution and asserting is done via the crate <a href="https://docs.rs/assert_cmd/latest/assert_cmd/">assert_cmd</a></li>
<li>the binary still exits with success, since I haven&rsquo;t added exit codes</li>
</ul>

<h3>Coverage report<a name="coverage-report"></h3>

<p>Coverage reports help to measure and observe how much of the code is actually covered. Based on those reports, it is easy
to tell for which branches tests need to be made.</p>

<p>The coverage profile can be enabled via environment variables, <a href="https://doc.rust-lang.org/rustc/instrument-coverage.html">as described in the docs</a></p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">RUSTFLAGS: <span class="s2">&#34;-C instrument-coverage&#34;</span> LLVM_PROFILE_FILE: <span class="s2">&#34;cargo-test-%p-%m.profraw&#34;</span> cargo <span class="nb">test</span>
</span></span></code></pre>
<p><sup class="footnote-ref" id="fnref:6"><a href="#fn:6">6</a></sup></p>

<p>The <a href="https://doc.rust-lang.org/rustc/instrument-coverage.html#installing-llvm-coverage-tools">llvm-coverage-tools</a> provide <code>rust-profdata</code> and <code>rust-cov</code> to process the generated raw coverage data. All those <code>*.profraw</code> files can be merged via <code>rust-profdata merge -sparse *.profraw -o coverage.profdata</code> and converted to html using <code>rust-cov show target/debug/blogstage -instr-profile=coverage.profdata --ignore-filename-regex=/.cargo --format=html --show-line-counts-or-regions &gt; coverage/index.html</code></p>

<p><img src="blogstage-static-web-server-in-rust_coverage.png"/></p>

<p>Unfortunately I didn&rsquo;t got the unittest covered, although they all passed. The integration tests on the other side worked out-of-the-box.</p>

<h2>Benchmark<a name="benchmark"></h2>

<p>If the files get cached in-memory and the service is tightly tailored around my use-case, you may ask <strong>Is it faster?</strong></p>

<p>Well, a tiny bit. I used <a href="https://github.com/mildsunrise/curl-benchmark">mildsunrise&rsquo;s curl-benchmark</a> with 100 requests and an insecure connection<sup class="footnote-ref" id="fnref:7"><a href="#fn:7">7</a></sup>:</p>

<p>caddy file serve:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">         DNS      TCP        SSL  Request           Content
</span></span><span class="line"><span class="cl">Code  lookup  connect  handshake     sent    TTFB  download
</span></span><span class="line"><span class="cl">min:     5.0     51.0       22.0     28.0    54.0       0.0
</span></span><span class="line"><span class="cl">avg:     5.7     55.6       35.8     32.2    60.1       1.1
</span></span><span class="line"><span class="cl">med:     5.0     55.0       36.0     32.0    60.0       1.0
</span></span><span class="line"><span class="cl">max:    15.0     67.0       45.0     41.0    86.0      10.0
</span></span><span class="line"><span class="cl">dev:   21.5%     5.5%      10.7%     8.1%    7.5%    106.1%
</span></span></code></pre>
<p>blogstage:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">         DNS      TCP        SSL  Request           Content
</span></span><span class="line"><span class="cl">Code  lookup  connect  handshake     sent    TTFB  download
</span></span><span class="line"><span class="cl">min:     5.0     51.0       26.0     28.0    58.0       0.0
</span></span><span class="line"><span class="cl">avg:     5.4     55.9       34.9     32.3    68.3       0.7
</span></span><span class="line"><span class="cl">med:     5.0     55.0       35.0     32.0    68.0       1.0
</span></span><span class="line"><span class="cl">max:     7.0     68.0       46.0     41.0    77.0       2.0
</span></span><span class="line"><span class="cl">dev:   12.3%     4.9%      11.2%     6.9%    5.9%     95.5%
</span></span></code></pre>
<h2>Wrap it up<a name="wrap-it-up"></h2>

<p><a href="https://github.com/RaphaelPour/blogstage/blob/980d84d096a0c9fe4b36186c71462f521c9ac848/src/main.rs"><code>src/main.rs</code></a>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">fs</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">net</span>::<span class="n">TcpListener</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">thread</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">blogstage</span>::<span class="n">on_request</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// https://doc.rust-lang.org/book/ch20-01-single-threaded.html
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="cm">/*</span><span class="cm"> parse arguments </span><span class="cm">*/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">uri</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">std</span>::<span class="n">env</span>::<span class="n">args</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">nth</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Some</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">uri</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">None</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;usage: blogstage &lt;URI&gt; &lt;PATH&gt;&#34;</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="k">return</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">std</span>::<span class="n">env</span>::<span class="n">args</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">nth</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Some</span><span class="p">(</span><span class="n">path</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">path</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">None</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;usage: blogstage &lt;URI&gt; &lt;PATH&gt;&#34;</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="k">return</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="cm">/*</span><span class="cm"> load files </span><span class="cm">*/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">raw_entries</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">fs</span>::<span class="n">read_dir</span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">entries</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">entries</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;error reading files from {}: {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">path</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="k">return</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">files</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">entry</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">raw_entries</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="o">!</span><span class="n">entry</span><span class="p">.</span><span class="n">as_ref</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">path</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">is_file</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="k">continue</span><span class="w"></span><span class="nl"></span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="n">files</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">entry</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="p">.</span><span class="n">as_ref</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="p">.</span><span class="n">file_name</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="p">.</span><span class="n">into_string</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">fs</span>::<span class="n">read</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">as_ref</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">path</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="cm">/*</span><span class="cm"> start server </span><span class="cm">*/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">listener</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">TcpListener</span>::<span class="n">bind</span><span class="p">(</span><span class="n">uri</span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">l</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">l</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;error on binding to {}: {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">uri</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="k">return</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="c1">// react to Ctrl+C
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="n">ctrlc</span>::<span class="n">set_handler</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">|</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="n">std</span>::<span class="n">process</span>::<span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">stream</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">listener</span><span class="p">.</span><span class="n">incoming</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="k">match</span><span class="w"> </span><span class="n">stream</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="nb">Ok</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="kd">let</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">files</span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="n">thread</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">|</span><span class="o">|</span><span class="w"> </span><span class="n">on_request</span><span class="p">(</span><span class="n">s</span><span class="p">,</span><span class="w"> </span><span class="n">f</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;error accepting connection: {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="k">continue</span><span class="w"></span><span class="nl"></span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<p><a href="https://github.com/RaphaelPour/blogstage/blob/980d84d096a0c9fe4b36186c71462f521c9ac848/src/main.rs"><code>src/lib.rs</code></a>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="p">{</span><span class="n">prelude</span>::<span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="n">BufReader</span><span class="p">,</span><span class="w"> </span><span class="n">Read</span><span class="p">,</span><span class="w"> </span><span class="n">Write</span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// We need to put everything out of main.rs what should be tested via integration tests:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="c1">// https://doc.rust-lang.org/book/ch11-03-test-organization.html#integration-tests-for-binary-crates
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">on_request</span><span class="p">(</span><span class="k">mut</span><span class="w"> </span><span class="n">stream</span>: <span class="nc">impl</span><span class="w"> </span><span class="n">Read</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Write</span><span class="p">,</span><span class="w"> </span><span class="n">files</span>: <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">u8</span><span class="o">&gt;</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">reader</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BufReader</span>::<span class="n">new</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="n">stream</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">request</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">_</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reader</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">.</span><span class="n">lines</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">result</span><span class="o">|</span><span class="w"> </span><span class="n">result</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">.</span><span class="n">take_while</span><span class="p">(</span><span class="o">|</span><span class="n">line</span><span class="o">|</span><span class="w"> </span><span class="o">!</span><span class="n">line</span><span class="p">.</span><span class="n">is_empty</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">target</span>: <span class="nb">String</span> <span class="o">=</span><span class="w"> </span><span class="n">request</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="sc">&#39; &#39;</span><span class="p">)</span><span class="p">.</span><span class="n">collect</span>::<span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="o">&amp;</span><span class="kt">str</span><span class="o">&gt;</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">[</span><span class="mi">1</span><span class="o">..</span><span class="p">]</span><span class="p">.</span><span class="n">to_string</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">target</span><span class="p">.</span><span class="n">is_empty</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="n">target</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&#34;index.html&#34;</span><span class="p">.</span><span class="n">into</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">mime</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mime_guess</span>::<span class="n">from_path</span><span class="p">(</span><span class="n">target</span><span class="p">.</span><span class="n">clone</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">.</span><span class="n">first</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">match</span><span class="w"> </span><span class="n">files</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="o">&amp;</span><span class="n">target</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Some</span><span class="p">(</span><span class="n">body</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">length</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">body</span><span class="p">.</span><span class="n">len</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;200 {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">target</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">stream</span><span class="p">.</span><span class="n">write_all</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;HTTP/1.1 200 OK\r\nContent-Length: {length}\r\nContent-Type: {mime}\r\n\r\n&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="p">.</span><span class="n">as_bytes</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">stream</span><span class="p">.</span><span class="n">write_all</span><span class="p">(</span><span class="n">body</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">None</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;404 {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">target</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">stream</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="p">.</span><span class="n">write_all</span><span class="p">(</span><span class="s">&#34;HTTP/1.1 404 NOT FOUND\r\n\r\n&#34;</span><span class="p">.</span><span class="n">as_bytes</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<h2>Vision<a name="vision"></h2>

<ul>
<li>compression: add additional gzip compression</li>
<li>refactor request parser: despite its bad readability, it e.g. fails if a filename contains spaces</li>
<li>eliminate unwraps: explicit error handling instead of &ldquo;resilience by accident&rdquo;</li>
</ul>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">like testing, coverage, release, ci,&hellip;</li>

<li id="fn:2">via <a href="https://github.com/RaphaelPour/blogctl">blogctl</a></li>

<li id="fn:3">see <a href="https://github.com/RaphaelPour/blogstage/commit/70a9c21e91e82dc86fb8c985931e06f5da53b3d8">70a9c21e</a></li>

<li id="fn:4">For simplifying the operation effort, I build a container containing the whole blog. I replaced the <a href="https://registry.hub.docker.com/_/caddy">caddy container</a> with an <a href="https://registry.hub.docker.com/_/alpine">alpine</a> one.</li>

<li id="fn:5">in comparison to the <a href="https://docs.rs/threadpool/latest/threadpool/">ThreadPool</a> approach of the <a href="https://doc.rust-lang.org/book/ch20-02-multithreaded.html">Multithreaded Server tutorial</a></li>

<li id="fn:6">Those environment variables can also be used for <code>cargo build</code> to generate a coverage binary.</li>

<li id="fn:7">python curl-benchmark.py &ndash; -L -k evilcookie.de`, somehow the SSL handshake didn&rsquo;t work&hellip;</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 08 Mar 2023 12:41:10 +0100</pubDate>
    </item>
    <item>
      <title>Finish rustlings</title>
      <link>https://evilcookie.de/finish-rustlings.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Finish rustlings</h1>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">+----------------------------------------------------+
</span></span><span class="line"><span class="cl">|          You made it to the Fe-nish line!          |
</span></span><span class="line"><span class="cl">+--------------------------  ------------------------+
</span></span><span class="line"><span class="cl">                          \\/
</span></span><span class="line"><span class="cl">     ▒▒          ▒▒▒▒▒▒▒▒      ▒▒▒▒▒▒▒▒          ▒▒
</span></span><span class="line"><span class="cl">   ▒▒▒▒  ▒▒    ▒▒        ▒▒  ▒▒        ▒▒    ▒▒  ▒▒▒▒
</span></span><span class="line"><span class="cl">   ▒▒▒▒  ▒▒  ▒▒            ▒▒            ▒▒  ▒▒  ▒▒▒▒
</span></span><span class="line"><span class="cl"> ░░▒▒▒▒░░▒▒  ▒▒            ▒▒            ▒▒  ▒▒░░▒▒▒▒
</span></span><span class="line"><span class="cl">   ▓▓▓▓▓▓▓▓  ▓▓      ▓▓██  ▓▓  ▓▓██      ▓▓  ▓▓▓▓▓▓▓▓
</span></span><span class="line"><span class="cl">     ▒▒▒▒    ▒▒      ████  ▒▒  ████      ▒▒░░  ▒▒▒▒
</span></span><span class="line"><span class="cl">       ▒▒  ▒▒▒▒▒▒        ▒▒▒▒▒▒        ▒▒▒▒▒▒  ▒▒
</span></span><span class="line"><span class="cl">         ▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒▒▒▒▒▒▒▒▓▓▒▒▓▓▒▒▒▒▒▒▒▒
</span></span><span class="line"><span class="cl">           ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
</span></span><span class="line"><span class="cl">             ▒▒▒▒▒▒▒▒▒▒██▒▒▒▒▒▒██▒▒▒▒▒▒▒▒▒▒
</span></span><span class="line"><span class="cl">           ▒▒  ▒▒▒▒▒▒▒▒▒▒██████▒▒▒▒▒▒▒▒▒▒  ▒▒
</span></span><span class="line"><span class="cl">         ▒▒    ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒    ▒▒
</span></span><span class="line"><span class="cl">       ▒▒    ▒▒    ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒    ▒▒    ▒▒
</span></span><span class="line"><span class="cl">       ▒▒  ▒▒    ▒▒                  ▒▒    ▒▒  ▒▒
</span></span><span class="line"><span class="cl">           ▒▒  ▒▒                      ▒▒  ▒▒
</span></span></code></pre>
<p>I just finished <a href="https://github.com/rust-lang/rustlings">rustlings</a>.</p>

<p>Some data:</p>

<ul>
<li>94 exercises about the rust language and standard library</li>
<li><a href="https://github.com/RaphaelPour/rustlings/">my solutions</a><sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup></li>
<li>from 13/01/2023 to 07/02/2023</li>
<li>15 commits</li>
<li>top three commits ranked by solved exercises:

<ul>
<li><a href="https://github.com/RaphaelPour/rustlings/commit/7053c4d9e284cfebca97cfc45e278e770503c294">21</a></li>
<li><a href="https://github.com/RaphaelPour/rustlings/commit/c9c35e8c8f1c8d97a104337756e064e7533e8c3f">15</a></li>
<li><a href="https://github.com/RaphaelPour/rustlings/commit/5191a228ee00f1fc88b99d5b034c2d8a9abc1c7e">14</a></li>
</ul></li>
</ul>

<h2>Rustlings</h2>

<p><img src="finish-rustlings_rustlings.png"/></p>

<p>I like the approach of rustlings in comparissons to other language learning &ldquo;platforms&rdquo; like <a href="exercism.io/">exercism</a> or <a href="https://adventofcode.com/">aoc</a><sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>.
There is a binary <code>rustlings</code> that is executed with the <code>watch</code> command showing a screen with the current progress such as the compiler output
of the current exercise. The output refreshes after each file change. An exercise consists of code that doesn&rsquo;t compile and/or has unsatisfied tests.</p>

<p>Due to the refreshing output and my two window setup (see image above; <code>rustlings watch</code> on the left, vim on the right), the feedback loop was very tight. Every exercise was mostly implemented but lacked
in some key lines that needed to be tweaked/added. This helped learning to read actual rust code and focus on the current lesson. Since rust has a bunch of
sophisticated concepts, it is good to not get overwhelmed by all the other stuff around the lesson.</p>

<h2>Rust impressions</h2>

<p>I read in <a href="https://doc.rust-lang.org/book/">the book</a>, used the <code>hint</code> commmand, guessed with trial-and-error and just applied the suggestions of the linter <a href="https://doc.rust-lang.org/stable/clippy/index.html">clippy</a>.</p>

<p>Rust is tough with all rich syntax and my main thought after this is: You are the garbabe collector. Since rust gurantees memory safety but has no garbage collector, the developer needs to tell the compiler that everything is
valid by e.g. <a href="https://doc.rust-lang.org/beta/rust-by-example/scope/borrow.html">borrowing</a> variables or defining <a href="https://doc.rust-lang.org/beta/rust-by-example/scope/lifetime.html">lifetimes</a>.</p>

<p>Thoughts despite <a href="hello-rust.html#thoughts">the ones of my first rust post</a>:</p>

<ul>
<li><a href="https://doc.rust-lang.org/rust-by-example/flow_control/match.html"><code>match</code></a> is not only a sophisticated switch case but it can also <a href="https://doc.rust-lang.org/rust-by-example/flow_control/match/destructuring/destructure_tuple.html">deconstruct</a> and <a href="https://doc.rust-lang.org/rust-by-example/flow_control/match/binding.html">bind</a></li>
<li><a href="https://doc.rust-lang.org/rust-by-example/custom_types/enum.html"><code>Enums</code></a> are not only &ldquo;symbols&rdquo; but can be all kinds of handy type with a struct. Together with <code>match</code>, <a href="https://doc.rust-lang.org/rust-by-example/flow_control/match/guard.html">this looks</a> promissing.</li>
</ul>

<p>Altough I want to do a few more rust projects to checkout the language with real use-cases, I can&rsquo;t imaging using it in my current every day life. As a gopher, the lack of runtime is not worth doing the garbage collection stuff.</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1"><p>Yes, I could&rsquo;ve forked it. But after naively cloning it I always refocused on rustlings
  than moving to a fork. Well, even right now I&rsquo;m writing this post instead of fixing it&hellip;</p></li>

<li id="fn:2">While it is not exactly a learning platform, I like to use it as such.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 07 Feb 2023 23:33:11 +0100</pubDate>
    </item>
    <item>
      <title>Thinking tools aka fidget toys</title>
      <link>https://evilcookie.de/thinking-tools-aka-fidget-toys.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Thinking tools aka fidget toys</h1>

<p>As my mind often needs something to do, I stumpled across fidget toys<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> as an alternative of chewing finger nails and excessive chewing gum usage<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>.</p>

<p>Anyway, I want to share my mostly self-printed thinking tools.</p>

<p><img src="thinking-tools-aka-fidget-toys_thinking_tools.jpg"/></p>

<p>My current ranking:</p>

<ol>
<li><a href="https://www.printables.com/model/928-yet-another-fidget-infinity-cube-v2">infinite fidget cube</a>: very satisfying to fold the cube infinitely many times</li>
<li><a href="https://www.printables.com/model/276901-joy-fidget">joy fidget</a>: reminds me of <a href="https://en.wikipedia.org/wiki/Nintendo_64">good old N64 times</a> while the stick&rsquo;s spring has a good feel</li>
<li>headless skrew with nut<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>: best if both hands need to do something</li>
<li>mini fascia roll<sup class="footnote-ref" id="fnref:4"><a href="#fn:4">4</a></sup>: good for muscle relaxation, it&rsquo;s the more sporty fidget toy</li>
<li>rubber duck: while it can be compressed quite satisfying, the sound is annyoing</li>
<li>classic fidget cube: the universal and classical cube you get when searching for those stuff, it&rsquo;s a bit too small for my hands</li>
<li><a href="https://www.printables.com/model/359925-approve-brick">approve brick</a>: this solid body is ok to keep hands busy but rather than that has no additional function</li>
</ol>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">probably best known for <a href="https://en.wikipedia.org/wiki/Fidget_spinner">fidget spinners</a></li>

<li id="fn:2">kind of a subconsious thing which is especially hard to control when brainstorming or concentrating</li>

<li id="fn:3">the remaining parts of my 3d-printed broken microphone stand</li>

<li id="fn:4">no advertisment here, just look for &lsquo;mini faszia roll&rsquo; using the search engine of your choice</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 18 Jan 2023 12:34:35 +0100</pubDate>
    </item>
    <item>
      <title>Hello rust</title>
      <link>https://evilcookie.de/hello-rust.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Hello rust</h1>

<p>I finally checked out <a href="https://www.rust-lang.org/">Rust</a> and solved <a href="https://adventofcode.com/2022/day/1">day one</a> of last year&rsquo;s advent of code.</p>

<p>tl;dr:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">fs</span>::<span class="n">File</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="p">{</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">prelude</span>::<span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="n">BufReader</span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// https://stackoverflow.com/a/45882510
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">io</span>::<span class="nb">Result</span><span class="o">&lt;</span><span class="p">(</span><span class="p">)</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="c1">// https://doc.rust-lang.org/std/vec/struct.Vec.html
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">calories</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">sum</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="c1">// https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#propagating-errors
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">File</span>::<span class="n">open</span><span class="p">(</span><span class="s">&#34;input&#34;</span><span class="p">)</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">file</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">file</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="k">in</span><span class="w">  </span><span class="n">BufReader</span>::<span class="n">new</span><span class="p">(</span><span class="n">file</span><span class="p">)</span><span class="p">.</span><span class="n">lines</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="nb">Ok</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">data</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="o">=</span><span class="w"> </span><span class="s">&#34;&#34;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">calories</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">sum</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="k">continue</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nl"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="c1">// https://doc.rust-lang.org/std/primitive.str.html#method.parse
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">        </span><span class="n">sum</span><span class="w"> </span><span class="o">+</span><span class="o">=</span><span class="w"> </span><span class="n">data</span><span class="p">.</span><span class="n">parse</span>::<span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">calories</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">calories</span><span class="p">.</span><span class="n">sort</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;part1: {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">calories</span><span class="p">.</span><span class="n">iter</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">rev</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">take</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="p">.</span><span class="n">sum</span>::<span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;part2: {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">calories</span><span class="p">.</span><span class="n">iter</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">rev</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">take</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="p">.</span><span class="n">sum</span>::<span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<p>Contents:</p>

<ul>
<li><a href="#motivation">Motivation</a></li>
<li><a href="#starting-over">Starting over</a></li>
<li><a href="#so-vs-official-docs">SO vs. official docs</a></li>
<li><a href="#investigate">Investigate</a>

<ul>
<li><a href="#immutable-first">Immutable first</a></li>
<li><a href="#error-handling">Error-handling</a></li>
<li><a href="#string-to-int">String to int</a></li>
</ul></li>
<li><a href="#expand-the-shortcuts">Expand the shortcuts</a></li>
<li><a href="#reaching-for-the-second-star">Reaching for the second star</a></li>
<li><a href="#thoughts">Thoughts</a></li>
</ul>

<h2>Motivation<a name="motivation"/></h2>

<p>As a C fanboy, I&rsquo;m interested in languages that have a similar low level scope. Since 2019, <a href="https://go.dev/">Go</a> is my language of choice where I made myself comfortable.</p>

<p>The claims and news brought me to Rust and today my curiousity about them took over:</p>

<ul>
<li><a href="https://lwn.net/Articles/910762/">linux kernel support</a></li>
<li><a href="https://prev.rust-lang.org/en-US/faq.html#does-rust-have-a-runtime">no runtime</a></li>
<li><a href="https://prev.rust-lang.org/en-US/faq.html#is-rust-garbage-collected">no garbage collector</a></li>
</ul>

<h2>Starting over<a name="starting-over"/></h2>

<p>To dive right into the language, I skipped all tutorials and exampls and started with day 1 of the last year&rsquo;s advent of code right away. Rust is already installed, so I started over by asking the internet for <a href="https://doc.rust-lang.org/stable/rust-by-example/std_misc/file/read_lines.html"><em>Rust line by line</em></a> and <a href="https://doc.rust-lang.org/std/cmp/fn.max.html"><em>Rust max value</em></a>, and here you are:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">fs</span>::<span class="n">File</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="p">{</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">BufRead</span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">path</span>::<span class="n">Path</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">cmp</span><span class="p">;</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// based on https://doc.rust-lang.org/stable/rust-by-example/std_misc/file/read_lines.html
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">max</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">sum</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">read_lines</span><span class="p">(</span><span class="s">&#34;input&#34;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">lines</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="k">if</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="o">=</span><span class="w"> </span><span class="s">&#34;&#34;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                    </span><span class="n">max</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cmp</span>::<span class="n">max</span><span class="p">(</span><span class="n">max</span><span class="p">,</span><span class="w"> </span><span class="n">sum</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                    </span><span class="n">sum</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                    </span><span class="k">continue</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nl"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="n">sum</span><span class="w"> </span><span class="o">+</span><span class="o">=</span><span class="w"> </span><span class="n">data</span><span class="p">.</span><span class="n">parse</span>::<span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">max</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cmp</span>::<span class="n">max</span><span class="p">(</span><span class="n">max</span><span class="p">,</span><span class="w"> </span><span class="n">sum</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;{}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">max</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">read_lines</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;</span><span class="p">(</span><span class="n">filename</span>: <span class="nc">P</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">io</span>::<span class="nb">Result</span><span class="o">&lt;</span><span class="n">io</span>::<span class="n">Lines</span><span class="o">&lt;</span><span class="n">io</span>::<span class="n">BufReader</span><span class="o">&lt;</span><span class="n">File</span><span class="o">&gt;</span><span class="o">&gt;</span><span class="o">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">where</span><span class="w"> </span><span class="n">P</span>: <span class="nb">AsRef</span><span class="o">&lt;</span><span class="n">Path</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">File</span>::<span class="n">open</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="n">io</span>::<span class="n">BufReader</span>::<span class="n">new</span><span class="p">(</span><span class="n">file</span><span class="p">)</span><span class="p">.</span><span class="n">lines</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<p>Looking more closely over the copy-pasta code, some constructs are standing out<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>:</p>

<ul>
<li><code>let mut max: i32 = 0;</code></li>
<li><code>if let Ok(lines) = read_lines(&quot;input&quot;) {</code></li>
<li><code>data.parse::&lt;i32&gt;().unwrap()</code></li>
<li><code>println!(&quot;{}, max)</code></li>
</ul>

<p>Don&rsquo;t forget the elephant <del>in the room</del> at the end. The last block seemed too complicated for simply reading a file line-by-line. Let&rsquo;s address this one first, as it&rsquo;s the greatest question mark for me.</p>

<h2>SO vs. official docs<a name="so-vs-official-docs"/></h2>

<p>Well, rather than addressing it, I asked the internet again as the code from the codes looked too optimized. <a href="https://stackoverflow.com/a/45882510">This SO post</a> was more reasonable than the <code>read_lines</code> section from the official documentation:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">fs</span>::<span class="n">File</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="p">{</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">prelude</span>::<span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="n">BufReader</span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">cmp</span><span class="p">;</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// based on https://doc.rust-lang.org/stable/rust-by-example/std_misc/file/read_lines.html
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">io</span>::<span class="nb">Result</span><span class="o">&lt;</span><span class="p">(</span><span class="p">)</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">max</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">sum</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">File</span>::<span class="n">open</span><span class="p">(</span><span class="s">&#34;input&#34;</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">reader</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BufReader</span>::<span class="n">new</span><span class="p">(</span><span class="n">file</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">reader</span><span class="p">.</span><span class="n">lines</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="o">=</span><span class="w"> </span><span class="s">&#34;&#34;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="n">max</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cmp</span>::<span class="n">max</span><span class="p">(</span><span class="n">max</span><span class="p">,</span><span class="w"> </span><span class="n">sum</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="n">sum</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">                </span><span class="k">continue</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nl"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">sum</span><span class="w"> </span><span class="o">+</span><span class="o">=</span><span class="w"> </span><span class="n">data</span><span class="p">.</span><span class="n">parse</span>::<span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">max</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cmp</span>::<span class="n">max</span><span class="p">(</span><span class="n">max</span><span class="p">,</span><span class="w"> </span><span class="n">sum</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;{}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">max</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<h2>Investigate<a name="investigate"/></h2>

<p>Let&rsquo;s get into all the remaining findings from <a href="#starting-over">starting over</a>.</p>

<h3>Immutable first<a name="immutable-first"/></h3>

<p>Variables are immutable/constant by default. A classical variables needs to be declared with <code>mut</code> for beeing mutable:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">max</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span></code></pre>
<h3>Error handling<a name="error-handling"/></h3>

<p>Error handling works by using <a href="https://doc.rust-lang.org/std/result/"><code>Results</code></a> containing the wanted data on success or an error. They can be assumed via <code>Ok</code> and <code>Err</code>, providing the wanted variable if it applies. In case of an error, the condition is false and never enters the branch:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">read_lines</span><span class="p">(</span><span class="s">&#34;input&#34;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span></code></pre>
<p>Alternatively by using <code>?</code> aka the <a href="https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator">question mark operator</a>, the error can implicitly be returned from
the current function:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">File</span>::<span class="n">open</span><span class="p">(</span><span class="s">&#34;input&#34;</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span></code></pre>
<p>This can be converted into a more explicit approach using <a href="https://doc.rust-lang.org/reference/expressions/match-expr.html"><code>match</code></a> where the success and failure case has its own arm.
An arm is kind of a lambda <code>&lt;pattern&gt; =&gt; &lt;expression&gt;</code>. The first pattern match gets selected and the corresponding expression executed. The <code>Err</code> and <code>Ok</code> do some kind of type-assertion including declaration of variables <code>e</code> and <code>file</code>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">File</span>::<span class="n">open</span><span class="p">(</span><span class="s">&#34;input&#34;</span><span class="p">)</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="n">file</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">file</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span></code></pre>
<h3>String to int<a name="string-to-int"/></h3>

<p>Converting a string into an integer needs some parsing. The <code>::&lt;&gt;</code> aka <a href="https://doc.rust-lang.org/book/appendix-02-operators.html?highlight=turbofish#non-operator-symbols">turbofish operator</a> is used to tell <code>parse</code> about the target type:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">data</span><span class="p">.</span><span class="n">parse</span>::<span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="w">
</span></span></span></code></pre>
<h2>Expand the shortcuts<a name="expand-the-shortcuts"/></h2>

<p>After expanding the error handling shortcuts, the code gets more transparent:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">fs</span>::<span class="n">File</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="p">{</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">prelude</span>::<span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="n">BufReader</span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">cmp</span><span class="p">;</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// https://stackoverflow.com/a/45882510
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">io</span>::<span class="nb">Result</span><span class="o">&lt;</span><span class="p">(</span><span class="p">)</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">max</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">sum</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="c1">// https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#propagating-errors
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">File</span>::<span class="n">open</span><span class="p">(</span><span class="s">&#34;input&#34;</span><span class="p">)</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">file</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">file</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">reader</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BufReader</span>::<span class="n">new</span><span class="p">(</span><span class="n">file</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">reader</span><span class="p">.</span><span class="n">lines</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="nb">Ok</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">data</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="o">=</span><span class="w"> </span><span class="s">&#34;&#34;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">max</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cmp</span>::<span class="n">max</span><span class="p">(</span><span class="n">max</span><span class="p">,</span><span class="w"> </span><span class="n">sum</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">sum</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="k">continue</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nl"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="c1">// https://doc.rust-lang.org/std/primitive.str.html#method.parse
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">        </span><span class="n">sum</span><span class="w"> </span><span class="o">+</span><span class="o">=</span><span class="w"> </span><span class="n">data</span><span class="p">.</span><span class="n">parse</span>::<span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">max</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cmp</span>::<span class="n">max</span><span class="p">(</span><span class="n">max</span><span class="p">,</span><span class="w"> </span><span class="n">sum</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;{}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">max</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<h2>Reaching for the second star<a name="reaching-for-the-second-star"/></h2>

<p>Finally I used a vector to solve the second aoc part:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">fs</span>::<span class="n">File</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="p">{</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">prelude</span>::<span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="n">BufReader</span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// https://stackoverflow.com/a/45882510
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">io</span>::<span class="nb">Result</span><span class="o">&lt;</span><span class="p">(</span><span class="p">)</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="c1">// https://doc.rust-lang.org/std/vec/struct.Vec.html
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">calories</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">sum</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="c1">// https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#propagating-errors
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">File</span>::<span class="n">open</span><span class="p">(</span><span class="s">&#34;input&#34;</span><span class="p">)</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="nb">Ok</span><span class="p">(</span><span class="n">file</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">file</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="k">in</span><span class="w">  </span><span class="n">BufReader</span>::<span class="n">new</span><span class="p">(</span><span class="n">file</span><span class="p">)</span><span class="p">.</span><span class="n">lines</span><span class="p">(</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="nb">Ok</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="o">&gt;</span><span class="w"> </span><span class="n">data</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="p">}</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="o">=</span><span class="w"> </span><span class="s">&#34;&#34;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">calories</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="n">sum</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">            </span><span class="k">continue</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nl"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">        </span><span class="c1">// https://doc.rust-lang.org/std/primitive.str.html#method.parse
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">        </span><span class="n">sum</span><span class="w"> </span><span class="o">+</span><span class="o">=</span><span class="w"> </span><span class="n">data</span><span class="p">.</span><span class="n">parse</span>::<span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">unwrap</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">calories</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="n">calories</span><span class="p">.</span><span class="n">sort</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;part1: {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">calories</span><span class="p">.</span><span class="n">iter</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">rev</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">take</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="p">.</span><span class="n">sum</span>::<span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;part2: {}&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">calories</span><span class="p">.</span><span class="n">iter</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">rev</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">take</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="p">.</span><span class="n">sum</span>::<span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nb">Ok</span><span class="p">(</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre>
<p>While the error handling takes a few lines, summing up the n-th last items of the vector are pretty ruby-alike short:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">calories</span><span class="p">.</span><span class="n">iter</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">rev</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">take</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="p">.</span><span class="n">sum</span>::<span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="w">
</span></span></span></code></pre>
<h2>Thoughts<a name="thoughts"/></h2>

<p>It was refreshing to checkout a new language including its resources and toolchain. The error handling with the <code>Ok</code> and <code>Err</code> construct is a mixture of the two error handling concepts I saw in other languages so far: try-catch and error value.
Although this looks promising for writing readable and maintainable code, I&rsquo;m far from judging.</p>

<p>The rustc compiler is colorful and includes some hints which supports my learning-by-doing approach.</p>

<p>Finally I&rsquo;m hyped and want to learn more about the language. Let&rsquo;s do some more days!</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">In context to Golang and C.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 03 Jan 2023 16:21:58 +0100</pubDate>
    </item>
    <item>
      <title>Femto retrospective</title>
      <link>https://evilcookie.de/femto-retrospective.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>femto - project showcase</h1>

<p><a href="https://github.com/RaphaelPour/femto">Femto</a> is a minimal CLI text editor made
in C with zero dependencies inspired by <a href="https://github.com/antirez/kilo">Antirez&rsquo;s kilo
editor</a>. This retrospective contains all
noteworthy progress made within this project starting from the idea until the &lsquo;end&rsquo;.</p>

<p>I&rsquo;ve created this post about a year ago, but never published it due to missing content/relevant information. Coming back a year later I see this from a different perspective. This is a good rough overview
before diving into the C source. The testing framework <em>cilicon</em> might be a good inspiration for unit-testing with C, too.</p>

<ul>
<li><a href="#general-information">General information</a></li>
<li><a href="#motivation">Motivation</a></li>
<li><a href="#internal-structure">Internal structure</a>

<ul>
<li><a href="#session">Session</a></li>
<li><a href="#screen">Screen</a></li>
<li><a href="#buffer">Buffer</a></li>
<li><a href="#terminal">Terminal</a></li>
<li><a href="#fileio">FileIO</a></li>
<li><a href="#ui">UI</a></li>
<li><a href="#helper">Helper</a></li>
</ul></li>
<li><a href="#cilicon">cilicon - unit test library</a>

<ul>
<li><a href="#thoughts">Thoughts</a></li>
</ul></li>
</ul>

<h2>General information<a name='general-information'/></h2>

<p>Features:</p>

<ul>
<li>open, create, save text files</li>
<li>navigation</li>
<li>edition</li>
</ul>

<p>Bugs:</p>

<ul>
<li>bad line wrapping</li>
<li>unknown escape sequences were printed to screen (e.g. Shift+Arrow key)</li>
<li>rare unhandeld glitches while editing</li>
</ul>

<p>Personal project outcome:</p>

<ul>
<li>deal with terminal&rsquo;s raw mode

<ul>
<li>use terminal as framebuffer</li>
<li>CLI dialogs</li>
</ul></li>
<li><a href="https://travis-ci.com/github/RaphaelPour/femto">CI testing</a> a C project</li>
<li>develop C unit testing lib <em>Cilicon</em></li>
<li>improve gdb skills to find and fix memory leaks</li>
</ul>

<h2>Motivation<a name='motivation'/></h2>

<ul>
<li>active C project to gain more experience</li>
<li>zero dependencies</li>
<li>text editors have a lot of feature potential (highlighting, tabs,
views, macros,&hellip;)</li>
<li>coping with the terminal&rsquo;s raw mode can be handy for further projects</li>
</ul>

<h2>Internal structure<a name='internal-structure'/></h2>

<p>Femto consists of seven components:</p>

<ul>
<li><a href="https://github.com/RaphaelPour/femto/blob/master/include/session.h">Session</a>:

<ul>
<li>provides abstract editor API</li>
<li>navigation</li>
<li>edition</li>
</ul></li>
<li><a href="https://github.com/RaphaelPour/femto/blob/master/include/screen.h">Screen</a>:

<ul>
<li>render framebuffer</li>
<li>update status bar</li>
<li>set cursors</li>
</ul></li>
<li><a href="https://github.com/RaphaelPour/femto/blob/master/include/buffer.h">Buffer</a>:

<ul>
<li>data+length structure</li>
<li>used as framebuffer</li>
</ul></li>
<li><a href="https://github.com/RaphaelPour/femto/blob/master/include/terminal.h">Terminal</a>:

<ul>
<li>control raw mode</li>
<li>provide user input, size and cursor position</li>
</ul></li>
<li><a href="https://github.com/RaphaelPour/femto/blob/master/include/fileio.h">FileIO</a>:

<ul>
<li>load file to internal representation</li>
<li>save file from internal representation</li>
</ul></li>
<li><a href="https://github.com/RaphaelPour/femto/blob/master/include/ui.h">UI</a>: Dialogs for user interaction</li>
<li><a href="https://github.com/RaphaelPour/femto/blob/master/include/helper.h">Helper</a>

<ul>
<li>logger</li>
<li>math functions (min,max,clamp, poor man&rsquo;s log10)</li>
</ul></li>
</ul>

<h3>Session<a name='session'/></h3>

<p>The <a href="https://github.com/RaphaelPour/femto/blob/master/include/session.h#L33">session type</a> contains the state of the running application:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* Name of the read file */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span> <span class="o">*</span><span class="n">filename</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Dimensions of the terminal */</span>
</span></span><span class="line"><span class="cl">    <span class="n">TerminalSize</span> <span class="n">terminal_size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Position on the screen */</span>
</span></span><span class="line"><span class="cl">    <span class="n">TerminalPosition</span> <span class="n">cursor_position</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Offset between file content and screen */</span>
</span></span><span class="line"><span class="cl">    <span class="n">TerminalPosition</span> <span class="n">offset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Array of lines which hold the content */</span>
</span></span><span class="line"><span class="cl">    <span class="n">Line</span> <span class="o">*</span><span class="n">lines</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">size_t</span> <span class="n">line_count</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Total length of all line lengths combined */</span>
</span></span><span class="line"><span class="cl">    <span class="n">size_t</span> <span class="n">content_length</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Dirty flag */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">dirty</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="n">Session</span><span class="p">;</span>
</span></span></code></pre>
<p>Any action a user makes affects this state.</p>

<ul>
<li><em>navigation</em> updates <code>cursor_position</code> and <code>offset</code></li>
<li><em>edition</em> updates the same as navigation plus <code>lines</code>,<code>line_count</code>, <code>content_length</code> and <code>dirty</code>.</li>
<li><em>save/load file</em> updates <code>filename</code> and <code>dirty</code></li>
</ul>

<h3>Screen<a name='screen'/></h3>

<ul>
<li>update output on terminal</li>
<li>generate status bar</li>
</ul>

<h3>Buffer<a name='buffer'/></h3>

<p>A simple data+length structure with functions to write more convenient to the data:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">typedef</span> <span class="k">struct</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span> <span class="o">*</span><span class="n">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="n">length</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="n">Buffer</span><span class="p">;</span>
</span></span></code></pre>
<p>This struture is currently only used by the screen module as framebuffer.</p>

<h3>Terminal<a name='terminal'/></h3>

<ul>
<li>enable/Disable Raw mode</li>
<li>determine terminal resolution</li>
<li>determine cursor position</li>
<li>get user input and replace it with a pseudo key if compound</li>
</ul>

<p>It&rsquo;s purpose overlaps with the screen module. Both are somehow manipulating the terminal&rsquo;s behaviour.</p>

<h3>FileIO<a name='fileio'/></h3>

<p>FileIO uses the filename given in the session object and stores the file&rsquo;s content into it.</p>

<h3>UI<a name='ui'/></h3>

<p>Handle dialogs including getting the users input, generating the right status bar and trigger a refresh.
It comes with two dialogs:</p>

<ul>
<li>safe file</li>
<li>quit (<em>do you really discard unsaved changes?</em>)</li>
</ul>

<p>Internally it has a generic dialog function which could be used to add more.</p>

<h3>Helper<a name='helper'/></h3>

<p>The helper has two major responisibilities:</p>

<ul>
<li>logging</li>
<li>provide shortcuts for often used mathematical functions</li>
</ul>

<p>The logger has a <code>printf</code> alike formatter function which automatically includes the module name and line number where the logger gets called.
This is accomplished by hiding the real formatter function behind a preprocessor directive which adds the module name and line number in place.</p>

<h2>cilicon - unit test library<a name='cilicon'/></h2>

<p>Cilicon is a <em>syntactic sugar library</em> which &lsquo;frames&rsquo; a unit test using concepts
like &lsquo;it&rsquo;, &lsquo;suite&rsquo; and &lsquo;expect_&hellip;&rsquo; inspired by ruby&rsquo;s rspec.</p>

<p>Each C module has it&rsquo;s own test suite represented in an extra test file. For
example the module <code>buffer</code> has it&rsquo;s own <code>test_suite_buffer</code> with the file
<code>buffer_test.c</code>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">test_create_buffer</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">TEST_IT_NAME</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">creates a buffer</span><span class="s">&#34;</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">Buffer</span> <span class="o">*</span><span class="n">buf</span> <span class="o">=</span> <span class="n">fe_create_buffer</span><span class="p">(</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="n">expect_not_null</span><span class="p">(</span> <span class="n">buf</span> <span class="p">)</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">fe_free_buffer</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">TEST_OK</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">test_append_to_buffer</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">TEST_IT_NAME</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">appends to a buffer</span><span class="s">&#34;</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">test_string</span> <span class="o">=</span> <span class="sa"></span><span class="s">&#34;</span><span class="s">const char *test_string</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">Buffer</span> <span class="o">*</span><span class="n">buf</span> <span class="o">=</span> <span class="n">fe_create_buffer</span><span class="p">(</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="n">expect_not_null</span><span class="p">(</span> <span class="n">buf</span> <span class="p">)</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">fe_append_to_buffer</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="n">test_string</span><span class="p">,</span> <span class="n">strlen</span><span class="p">(</span><span class="n">test_string</span><span class="p">)</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span> <span class="o">!</span> <span class="n">expect_b_eq</span><span class="p">(</span> <span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span> <span class="n">test_string</span><span class="p">,</span> <span class="n">buf</span><span class="o">-</span><span class="o">&gt;</span><span class="n">data</span><span class="p">,</span> <span class="n">strlen</span><span class="p">(</span> <span class="n">test_string</span> <span class="p">)</span><span class="p">,</span> <span class="n">buf</span><span class="o">-</span><span class="o">&gt;</span><span class="n">length</span>  <span class="p">)</span><span class="p">)</span> <span class="k">goto</span> <span class="n">cleanup</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">TEST_OK</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nl">cleanup</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">fe_free_buffer</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">test_suite_buffer</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">TEST_SUITE_NAME</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">Buffer</span><span class="s">&#34;</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">test_create_buffer</span><span class="p">(</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">test_append_to_buffer</span><span class="p">(</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Which outputs the following on success:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">---- Buffer ----
</span></span><span class="line"><span class="cl">it creates a buffer                      OK
</span></span><span class="line"><span class="cl">it appends to a buffer                   OK
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ALL PASSED
</span></span></code></pre>
<p>And on failure:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">---- Buffer ----
</span></span><span class="line"><span class="cl">it creates a buffer                      OK
</span></span><span class="line"><span class="cl">it appends to a buffer                   FAIL
</span></span><span class="line"><span class="cl">Expected equal buffers, got unequal.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">1 of 2 expects failed.
</span></span><span class="line"><span class="cl">FATALITY
</span></span></code></pre>
<h3>Thoughts<a name='thoughts'/></h3>

<ul>
<li>Having some convenience features on writing tests is key for C since there is nothing one can build from with zero dependencies.</li>
<li><code>Goto</code> is bad. <a href="https://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-in-Linux-Kernel-Code/">Isn&rsquo;t it?</a> But there are cases where <code>goto</code> is better than for example <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">wet</a> code. Big C projects like the <a href="https://github.com/torvalds/linux">linux kernel</a> or <a href="https://github.com/qemu/qemu">qemu</a> use <code>goto</code> for implementing clean ups. For example qemu&rsquo;s <a href="https://github.com/qemu/qemu/blob/1f7c02797fa189ce4b34382020bbce63262a5758/qemu-img.c#L515">img_create</a>.</li>
<li>A year later, I&rsquo;m not using femto at all. I though about using it for commit messages or at least when administrating my servers to let new use-cases and valuable feature ideas evolve, but nope. But that is ok.</li>
</ul>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 02 Jan 2023 16:20:40 +0100</pubDate>
    </item>
    <item>
      <title>Parametric eurorack blank plate with OpenSCAD</title>
      <link>https://evilcookie.de/parametric-eurorack-blank-plate-with-openscad.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Parametric eurorack blank plate with OpenSCAD</h1>

<p>I&rsquo;ve designed a 3d-printable parametric eurorack blank plate including my artist name with <a href="https://openscad.org/">OpenSCAD</a>.</p>

<p><img src="parametric-eurorack-blank-plate-with-openscad_impression_parametric_eurorack_blank_plate.jpg"/></p>

<h2>Motivation</h2>

<p>After arranging the eurorack modules in a case there may be a bunch of gaps that can be filled using  blank plates.
Since eurorack is already a cost-intensive hobby<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>, I though about printing it myself with the advantage of choosing the design.</p>

<p>OpenSCAD makes it easy to parameterize a modell<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> and make it more or less transparent, depending on the code quality.</p>

<p>Some data (and ads):</p>

<ul>
<li><a href="https://prusaverse-s3-production-eu-central-1.s3.eu-central-1.amazonaws.com/media/prints/349859/stls/2973491_27f4c842-cfcd-4d28-b1a0-5465c1c251a3/eurorack_plate_noisetaeter.scad">openscad file</a></li>
<li><a href="https://www.printables.com/model/349859-parametric-eurorack-8hp-plate-noisetater">model on printables</a></li>
<li><a href="https://www.modulargrid.net/e/racks/view/1828783">current eurorack</a></li>
<li><a href="https://soundcloud.com/noise-taeter">soundcloud profile</a></li>
</ul>

<h2>Parameters</h2>

<ul>
<li><code>$HPUnits</code>: count of HP units for the width of the base plate</li>
<li>label: text on the base plate which is optimized for 8HP</li>
</ul>

<h2>Base plate</h2>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cm">/* 
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Eurorack format is 128.5mm high (3xU) and consists of
</span></span></span><span class="line"><span class="cl"><span class="cm"> * a width with a multiple of 5.08mm (1xHP). M3 bolts 
</span></span></span><span class="line"><span class="cl"><span class="cm"> * are used
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$U3</span> <span class="o">=</span> <span class="mf">128.5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$HP1</span> <span class="o">=</span> <span class="mf">5.08</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$M3r</span> <span class="o">=</span> <span class="mi">3</span><span class="o">/</span><span class="mi">2</span><span class="o">+</span><span class="mf">0.15</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$holeXPadding</span> <span class="o">=</span> <span class="mf">1.4</span><span class="o">+</span><span class="nv">$M3r</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$holeYPadding</span> <span class="o">=</span> <span class="mf">1.5</span><span class="o">+</span><span class="nv">$M3r</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$HPUnits</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$depth</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$width</span> <span class="o">=</span> <span class="nv">$HPUnits</span> <span class="o">*</span> <span class="nv">$HP1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$font</span><span class="o">=</span><span class="s2">&#34;</span><span class="s2">DejaVu Sans:style=Book</span><span class="s2">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm"> * base plate
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">difference</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="cm">/* plate */</span>
</span></span><span class="line"><span class="cl"><span class="nx">cube</span><span class="p">([</span><span class="nv">$width</span><span class="p">,</span><span class="nv">$U3</span><span class="p">,</span><span class="nv">$depth</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl"><span class="cm">/* bolt holes */</span>
</span></span><span class="line"><span class="cl"><span class="nx">translate</span><span class="p">([</span><span class="nv">$holeXPadding</span><span class="p">,</span><span class="nv">$holeYPadding</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="nx">cylinder</span><span class="p">(</span><span class="nx">r</span><span class="o">=</span><span class="nv">$M3r</span><span class="p">,</span> <span class="nx">h</span><span class="o">=</span><span class="nv">$depth</span><span class="o">+</span><span class="mi">2</span><span class="p">,</span> <span class="nv">$fn</span><span class="o">=</span><span class="mi">40</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl"><span class="nx">translate</span><span class="p">([</span><span class="nv">$width</span><span class="o">-</span><span class="p">(</span><span class="mf">5.6</span><span class="o">+</span><span class="nv">$M3r</span><span class="p">),</span><span class="nv">$holeYPadding</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="nx">cylinder</span><span class="p">(</span><span class="nx">r</span><span class="o">=</span><span class="nv">$M3r</span><span class="p">,</span> <span class="nx">h</span><span class="o">=</span><span class="nv">$depth</span><span class="o">+</span><span class="mi">2</span><span class="p">,</span> <span class="nv">$fn</span><span class="o">=</span><span class="mi">40</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl"><span class="nx">translate</span><span class="p">([</span><span class="nv">$width</span><span class="o">-</span><span class="p">(</span><span class="mf">5.6</span><span class="o">+</span><span class="nv">$M3r</span><span class="p">),</span><span class="nv">$U3</span><span class="o">-</span><span class="nv">$holeYPadding</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="nx">cylinder</span><span class="p">(</span><span class="nx">r</span><span class="o">=</span><span class="nv">$M3r</span><span class="p">,</span> <span class="nx">h</span><span class="o">=</span><span class="nv">$depth</span><span class="o">+</span><span class="mi">2</span><span class="p">,</span> <span class="nv">$fn</span><span class="o">=</span><span class="mi">40</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl"><span class="nx">translate</span><span class="p">([</span><span class="nv">$holeXPadding</span><span class="p">,</span><span class="nv">$U3</span><span class="o">-</span><span class="nv">$holeYPadding</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="nx">cylinder</span><span class="p">(</span><span class="nx">r</span><span class="o">=</span><span class="nv">$M3r</span><span class="p">,</span> <span class="nx">h</span><span class="o">=</span><span class="nv">$depth</span><span class="o">+</span><span class="mi">2</span><span class="p">,</span> <span class="nv">$fn</span><span class="o">=</span><span class="mi">40</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<h2>Label</h2>

<p>To make an appealing design with my artist name, I repeated it a few time horizontally and make it overlapping. As a detail, the german umlaut &lsquo;Ä&rsquo; is only repeated once and mirrored at the dots.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nx">translate</span><span class="p">([</span><span class="nv">$width</span><span class="o">-</span><span class="nv">$holeYPadding</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="nv">$depth</span><span class="o">/</span><span class="mf">1.5</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nx">rotate</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">90</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nx">linear_extrude</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nx">scale</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nx">text</span><span class="p">(</span> <span class="s2">&#34;</span><span class="s2">             Ä   </span><span class="s2">&#34;</span> <span class="p">,</span><span class="nx">font</span><span class="o">=</span><span class="nv">$font</span><span class="p">,</span> <span class="nx">size</span><span class="o">=</span><span class="mf">12.25</span><span class="p">,</span> <span class="nx">direction</span><span class="o">=</span><span class="s2">&#34;</span><span class="s2">ltr</span><span class="s2">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">translate</span><span class="p">([</span><span class="nv">$holeYPadding</span><span class="o">+</span><span class="mi">2</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="nv">$depth</span><span class="o">/</span><span class="mf">1.5</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nx">rotate</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">90</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nx">linear_extrude</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nx">scale</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nx">text</span><span class="p">(</span> <span class="s2">&#34;</span><span class="s2">             Ä   </span><span class="s2">&#34;</span> <span class="p">,</span><span class="nx">font</span><span class="o">=</span><span class="nv">$font</span><span class="p">,</span> <span class="nx">size</span><span class="o">=</span><span class="mf">12.25</span><span class="p">,</span> <span class="nx">direction</span><span class="o">=</span><span class="s2">&#34;</span><span class="s2">ltr</span><span class="s2">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="nx">xOffset</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="o">:</span><span class="mi">2</span><span class="o">:</span><span class="mi">8</span><span class="p">]){</span>
</span></span><span class="line"><span class="cl">    <span class="nx">translate</span><span class="p">([</span><span class="nv">$width</span><span class="o">-</span><span class="nv">$holeYPadding</span><span class="o">*</span><span class="nx">xOffset</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="nv">$depth</span><span class="o">/</span><span class="mf">1.5</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="nx">rotate</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">90</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="nx">linear_extrude</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">scale</span><span class="p">([</span><span class="mf">1.125</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="nx">text</span><span class="p">(</span> <span class="s2">&#34;</span><span class="s2">NOISET  TER</span><span class="s2">&#34;</span> <span class="p">,</span><span class="nx">font</span><span class="o">=</span><span class="nv">$font</span><span class="p">,</span> <span class="nx">size</span><span class="o">=</span><span class="mi">12</span><span class="p">,</span> <span class="nx">direction</span><span class="o">=</span><span class="s2">&#34;</span><span class="s2">ltr</span><span class="s2">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<div class="footnotes">

<hr>

<ol>
<li id="fn:1"><a href="https://www.thomann.de/intl/doepfer_a_100_b8.htm">Doepfer A-100 B8</a> costs about 4.20EUR (excl. shipping) as of 31.12.2022.</li>

<li id="fn:2">I noticed, that traditional WYSIWYG-CAD-Modeller (like <a href="https://www.freecadweb.org/">FreeCAD</a> or <a href="https://www.autodesk.com/products/fusion-360/overview">Fusion 360</a>), can provide parameterization, too.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 28 Dec 2022 07:58:20 +0100</pubDate>
    </item>
    <item>
      <title>aoc2022-5 - generic stack</title>
      <link>https://evilcookie.de/aoc2022-5---generic-stack.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>aoc2022-5 - generic stack</h1>

<p>This puzzle can be solved straight forward by implementing a stack and process the move instructions properly.
Since it is past august 2022<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>, let&rsquo;s implement it with generics to make it type-independent:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Stack</span><span class="p">[</span><span class="nx">T</span> <span class="nx">any</span><span class="p">]</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">items</span> <span class="p">[</span><span class="p">]</span><span class="nx">T</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>The first array element of <code>item</code> is the bottom of the stack, while the last item represents the top. For completeness, during initialization,
the items are read in reverse order, so a <code>PushAhead</code> function is needed which adds an item at the beginning of the array.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="o">*</span><span class="nx">Stack</span><span class="p">[</span><span class="nx">T</span><span class="p">]</span><span class="p">)</span> <span class="nf">PushAhead</span><span class="p">(</span><span class="nx">item</span> <span class="nx">T</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">s</span><span class="p">.</span><span class="nx">items</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="p">[</span><span class="p">]</span><span class="nx">T</span><span class="p">{</span><span class="nx">item</span><span class="p">}</span><span class="p">,</span> <span class="nx">s</span><span class="p">.</span><span class="nx">items</span><span class="o">...</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<h2>star 1 - business as usual</h2>

<p><em>Problem</em>: The first star requires to move each item separately between the stacks.</p>

<p><em>Solution</em>: Iteratively <code>pop</code> each item from the source stack and <code>push</code> it onto the destination one.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="o">*</span><span class="nx">Stack</span><span class="p">[</span><span class="nx">T</span><span class="p">]</span><span class="p">)</span> <span class="nf">Push</span><span class="p">(</span><span class="nx">item</span> <span class="nx">T</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">s</span><span class="p">.</span><span class="nx">items</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">items</span><span class="p">,</span> <span class="nx">item</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="o">*</span><span class="nx">Stack</span><span class="p">[</span><span class="nx">T</span><span class="p">]</span><span class="p">)</span> <span class="nf">Pop</span><span class="p">(</span><span class="p">)</span> <span class="nx">T</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">item</span> <span class="o">:=</span> <span class="nx">s</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">items</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="nx">s</span><span class="p">.</span><span class="nx">items</span> <span class="p">=</span> <span class="nx">s</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="p">:</span><span class="nb">len</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">items</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">item</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<h2>star 2 - chain the supplies</h2>

<p><em>Problem</em>: All items contained in an move instruction should be pushed at once (chained) to the destination stack, remaining in the same order.</p>

<p><em>Solution</em>: <code>Pop</code> and <code>Push</code> multiple items at once via <code>PushN</code> and <code>PopN</code>.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="o">*</span><span class="nx">Stack</span><span class="p">[</span><span class="nx">T</span><span class="p">]</span><span class="p">)</span> <span class="nf">PushN</span><span class="p">(</span><span class="nx">items</span> <span class="p">[</span><span class="p">]</span><span class="nx">T</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">s</span><span class="p">.</span><span class="nx">items</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">items</span><span class="p">,</span> <span class="nx">items</span><span class="o">...</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="o">*</span><span class="nx">Stack</span><span class="p">[</span><span class="nx">T</span><span class="p">]</span><span class="p">)</span> <span class="nf">PopN</span><span class="p">(</span><span class="nx">l</span> <span class="kt">int</span><span class="p">)</span> <span class="p">[</span><span class="p">]</span><span class="nx">T</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">items</span> <span class="o">:=</span> <span class="nb">append</span><span class="p">(</span><span class="p">[</span><span class="p">]</span><span class="nx">T</span><span class="p">{</span><span class="p">}</span><span class="p">,</span><span class="nx">s</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">items</span><span class="p">)</span><span class="o">-</span><span class="nx">l</span><span class="p">:</span><span class="p">]</span><span class="o">...</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">s</span><span class="p">.</span><span class="nx">items</span> <span class="p">=</span> <span class="nx">s</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="p">:</span><span class="nb">len</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">items</span><span class="p">)</span><span class="o">-</span><span class="nx">l</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">items</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Generics got finally introduced with <a href="https://go.dev/blog/go1.19">go 1.19</a>.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 06 Dec 2022 17:08:13 +0100</pubDate>
    </item>
    <item>
      <title>aoc2022 - reaching for the stars (again)</title>
      <link>https://evilcookie.de/aoc2022---reaching-for-the-stars-again.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>aoc22-1 - reaching for the stars (again)</h1>

<p><a href="https://adventofcode.com/2022/day/1">This year&rsquo;s AoC</a> starts right in the rain forest with a nutrition puzzle.</p>

<p><em>Problem</em>: Find the elves (one for part 1 and three for part 2) carrying the most calories.</p>

<p><em>Solution</em>:</p>

<ul>
<li>Part 1: Find the maximum sum.</li>
<li>Part 2: Store all sums sorted in an array and sum the highest three.</li>
</ul>

<h2>Stellar</h2>

<p>I created a utility lib for reoccurring problems: <a href="https://github.com/RaphaelPour/stellar">Stellar</a>. While the puzzle such as pretty trivial, extracting and generalizing the &lsquo;find-max-n-values&rsquo; approach was more interesting.</p>

<p><a href="https://github.com/RaphaelPour/aoc2022/blame/08859e206ce553f832a266ccf8a06099dc5a0175/days/01/part.go#L27">Original solution</a>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">part2</span><span class="p">(</span><span class="nx">data</span> <span class="p">[</span><span class="p">]</span><span class="kt">string</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">calories</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="p">[</span><span class="p">]</span><span class="kt">int</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...add all sums to the calories array 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">  <span class="nx">sort</span><span class="p">.</span><span class="nf">Ints</span><span class="p">(</span><span class="nx">calories</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">l</span> <span class="o">:=</span> <span class="nb">len</span><span class="p">(</span><span class="nx">calories</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">calories</span><span class="p">[</span><span class="nx">l</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="nx">calories</span><span class="p">[</span><span class="nx">l</span><span class="o">-</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="nx">calories</span><span class="p">[</span><span class="nx">l</span><span class="o">-</span><span class="mi">3</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p><a href="https://github.com/RaphaelPour/stellar/blob/156793ae3fc65ebcba139babf0a6e8b021215f79/math/math.go#L71">Generic max-n solution for Stellar</a>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nx">MaxN</span><span class="p">[</span><span class="nx">T</span> <span class="nx">Number</span><span class="p">]</span><span class="p">(</span><span class="nx">nums</span> <span class="p">[</span><span class="p">]</span><span class="nx">T</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">int</span><span class="p">)</span> <span class="p">[</span><span class="p">]</span><span class="nx">T</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="nx">nums</span><span class="p">)</span> <span class="p">&lt;</span> <span class="nx">n</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">sort</span><span class="p">.</span><span class="nf">Slice</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="nx">j</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">nums</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="p">&gt;</span> <span class="nx">nums</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span> <span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">nums</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="nx">n</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p><a href="https://github.com/RaphaelPour/aoc2022/blob/0eb2f3f7a2a5dbde69f4ece62841c3c788e3983b/days/01/part.go#L11">Solution using MaxN</a>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">maxCalories</span><span class="p">(</span><span class="nx">data</span> <span class="p">[</span><span class="p">]</span><span class="kt">string</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">calories</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="p">[</span><span class="p">]</span><span class="kt">int</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">currentCalories</span> <span class="o">:=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">row</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">data</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nx">row</span> <span class="o">!=</span> <span class="s">&#34;&#34;</span> <span class="o">&amp;&amp;</span> <span class="nx">i</span> <span class="p">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">currentCalories</span> <span class="o">+=</span> <span class="nx">strings</span><span class="p">.</span><span class="nf">ToInt</span><span class="p">(</span><span class="nx">row</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">continue</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">calories</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">calories</span><span class="p">,</span> <span class="nx">currentCalories</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">currentCalories</span> <span class="p">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">math</span><span class="p">.</span><span class="nf">Sum</span><span class="p">(</span><span class="nx">math</span><span class="p">.</span><span class="nf">MaxN</span><span class="p">(</span><span class="nx">calories</span><span class="p">,</span> <span class="nx">n</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>For completeness, I also added <a href="https://github.com/RaphaelPour/stellar/blob/main/math/math.go#L80">MinN</a> by inverting the sort comparison:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nx">MinN</span><span class="p">[</span><span class="nx">T</span> <span class="nx">Number</span><span class="p">]</span><span class="p">(</span><span class="nx">nums</span> <span class="p">[</span><span class="p">]</span><span class="nx">T</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">int</span><span class="p">)</span> <span class="p">[</span><span class="p">]</span><span class="nx">T</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="nx">nums</span><span class="p">)</span> <span class="p">&lt;</span> <span class="nx">n</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">sort</span><span class="p">.</span><span class="nf">Slice</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="nx">j</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">nums</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="p">&lt;</span> <span class="nx">nums</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span> <span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">nums</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="nx">n</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Thu, 01 Dec 2022 08:50:49 +0100</pubDate>
    </item>
    <item>
      <title>rework of verbose</title>
      <link>https://evilcookie.de/rework-of-verbose.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Rework of verbose</h1>

<p><a href="verbose.raphaelpour.de">Verbose</a> is my vocabulary web service to memorize and look up new and interesting english words. Since I&rsquo;m continuously containerize my services , I stumpled across this service depending on nginx, php and mysql. Verbose was intended to be a non-fancy and simple project, so I rather thought about
the requirements and reworked a proper docker-native solution than running a bunch of containers.</p>

<p><img src="rework-of-verbose_verbose.png"/></p>

<h2>History</h2>

<p>I started to read english books<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> to improve my language skills. But as the amount of new words grew, it felt like reading progress slowed down continously due to repeated look ups and high amount of new words to learn.</p>

<p>At first I cached all the lookups in a text file, then only added interesting, elegant or notable words to lower the total amount. Later I built a web service that simply provides an form to add new words and showed a list of all words so far. A text file could&rsquo;ve been enough, but you know, having a project with a real use-case gives a developer computer science student the feeling of doing something that matters rather than just implementing demos or theoretical/fictional use-cases.</p>

<p>There were tons of features that could be nice for the service. But the goal of this project was to focus on the main use-case and avoid <a href="https://buttondown.email/hillelwayne/archive/edge-case-poisoning/">edge case posoning</a>. I had literally thousand of software projects in my developer life but only a hand full grew to something noteworthy or actually useful. Although it was hard to give up (or let&rsquo;s say postpone) all the exciting ideas and just implement an <a href="https://en.wikipedia.org/wiki/Minimum_viable_product">MVP</a>, the long-term experience of having a useful tool where <code>time of use &gt;&gt; time of development</code> was great.</p>

<p>There were only two optional features added: word-of-the-pageload and count of words at the bottom.</p>

<h2>Original setup</h2>

<p>The <a href="verbose.raphaelpour.de">web site</a> was built with <a href="https://getbootstrap.com/">bootstrap</a> to quickly create an appealing look without investing too much time with CSS. The backend was made with PHP providing the translations from the <a href="https://mariadb.org/">MariaDB</a> database to the frontend and storing new once from the form secured with <a href="https://en.wikipedia.org/wiki/.htaccess">htaccess</a>.</p>

<p>The backend only had two routes:</p>

<ul>
<li><code>GET /</code>: view web site with all translations</li>
<li><code>POST add.php</code>: add a new translation</li>
</ul>

<p>The database schema was fairly simple:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="o">`</span><span class="n">vocabulary</span><span class="o">`</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="o">`</span><span class="n">id</span><span class="o">`</span><span class="w"> </span><span class="nb">int</span><span class="p">(</span><span class="mi">11</span><span class="p">)</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="w"> </span><span class="n">AUTO_INCREMENT</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="o">`</span><span class="n">de</span><span class="o">`</span><span class="w"> </span><span class="nb">varchar</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="o">`</span><span class="n">en</span><span class="o">`</span><span class="w"> </span><span class="nb">varchar</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="o">`</span><span class="n">added</span><span class="o">`</span><span class="w"> </span><span class="k">timestamp</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="k">CURRENT_TIMESTAMP</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="w"> </span><span class="p">(</span><span class="o">`</span><span class="n">id</span><span class="o">`</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w"> </span><span class="n">ENGINE</span><span class="o">=</span><span class="n">InnoDB</span><span class="w"> </span><span class="n">AUTO_INCREMENT</span><span class="o">=</span><span class="mi">0</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="n">CHARSET</span><span class="o">=</span><span class="n">utf8</span><span class="p">;</span><span class="w">
</span></span></span></code></pre>
<p>The old setup can be found <a href="https://github.com/RaphaelPour/verbose/tree/e17213823080527b3b3f1527f98099d93cba9b04">here</a>.</p>

<h2>Reworked setup</h2>

<p>The frontend remained the same. The backend was completely replaced with a containerized go binary providing the web site plus a REST-API for using the translations programatically. The relational database table was replaced with a simple data structure which is un-/marshalled<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> to JSON and stored within a docker volume. Generally it is not a good idea to use a file-based storage backend for a public available web service when implemented naively. I/O is very time consuming compared by having the data in-memory or requesting a service that has it in-memory. But on average I view it once a day and add only one word per month. Reading the file only on start up and writing it only on adding a new word to get rid of a database server was a fair compromise.</p>

<p>Data structure:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Translation</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Words</span> <span class="p">[</span><span class="p">]</span><span class="kt">string</span> <span class="s">`</span><span class="s">json:&#34;words&#34;</span><span class="s">`</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Vocabulary</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Entries</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="nx">Translation</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Snipptet from the JSON file:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;Fun&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;words&#34;</span><span class="p">:</span> <span class="p">[</span> <span class="s2">&#34;Spaß&#34;</span> <span class="p">]</span> <span class="p">}</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;adorable&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;words&#34;</span><span class="p">:</span> <span class="p">[</span> <span class="s2">&#34;bezaubernd&#34;</span><span class="p">,</span> <span class="s2">&#34;liebenswert&#34;</span> <span class="p">]</span> <span class="p">}</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;done&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;words&#34;</span><span class="p">:</span> <span class="p">[</span> <span class="s2">&#34;fertig&#34;</span> <span class="p">]</span> <span class="p">}</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;verbose&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;words&#34;</span><span class="p">:</span> <span class="p">[</span> <span class="s2">&#34;quasseln&#34;</span> <span class="p">]</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Routes:</p>

<ul>
<li>Web site:

<ul>
<li><code>GET /</code>: view web site with all translations</li>
<li><code>POST /new</code>: add new translation</li>
</ul></li>
<li>REST-API:

<ul>
<li><code>GET /api/v1/words</code>: get all words</li>
<li><code>GET /api/v1/words/&lt;en word</code>: get a translation for a given english word</li>
<li><code>POST /api/v1/words/&lt;en word&gt;</code>: add new translation</li>
</ul></li>
</ul>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1"><a href="https://www.goodreads.com/book/show/13.The_Ultimate_Hitchhiker_s_Guide_to_the_Galaxy">Hitchhiker&rsquo;s Guide to the galaxy from Douglas Adams</a> and <a href="https://www.goodreads.com/book/show/52696249-animal-farm">Animal Farm by George Orwell</a></li>

<li id="fn:2">un-/marshalling are the <a href="https://go.dev/blog/json">go equivalent</a> of de-/serialization of data</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 09 Sep 2022 12:54:08 +0200</pubDate>
    </item>
    <item>
      <title>godot wild jam 48</title>
      <link>https://evilcookie.de/godot-wild-jam-48.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>godot wild jam 48 - crack in the shell</h1>

<p><a href="https://github.com/Tch1b0">Johannes</a> and I participated at the <a href="https://itch.io/jam/godot-wild-jam-48">godot wild jam 48</a> having the theme <em>moon</em>.
Our submission is <a href="https://itch.io/jam/godot-wild-jam-48/rate/1670064">Crack in the shell</a>: <em>A race against time
in space. Will the oxygen last to get back to the base?</em></p>

<ul>
<li><a href="https://itch.io/jam/godot-wild-jam-48/rate/1670064">jam submission</a></li>
<li><a href="https://tch1b0.itch.io/crack-in-the-shell">game</a></li>
<li><a href="https://github.com/Glow-Project/gwj-48">source</a></li>
<li>soundtracks: <a href="https://soundcloud.com/noise-taeter/welcome-to-the-moon">Welcome to the moon</a>, <a href="https://soundcloud.com/noise-taeter/wrong-path">Wrong path</a></li>
</ul>

<h2>Internals</h2>

<h3>Dall-E Logo</h3>

<p>Since Johannes has a beta-subscription for Dall-E, we were a bit curious and tried to generate interesting logos.
We ended up with <em>Closeup of an astronaut helmet flying towards a black hole, 8k, award winning</em> and chose <a href="https://labs.openai.com/s/691FEP4ybAx8eZQuc726qHq1">the third one</a>:</p>

<p><img src="godot-wild-jam-48_dalle_astronaut.png"/></p>

<h3>Atmosphere</h3>

<p>We wanted to make an immersive 3D game on the moon. But we knew our abilities creating a convincing atmosphere are limited. So we tried creating immersion by balancing <em>sensory overload</em> with <em>controlled guiding</em>. Lastly the sound- and audio design helped us to gain more space aesthetics.</p>

<h4>Sensory overload</h4>

<p><em>Intro, breathing noises, alarm, red blinking lights, &ldquo;warning, oxygen tank damaged&rdquo;.</em></p>

<p>You need to survive while oxygen is almost empty and without any orientation. Basically an oversimplified labyrinth with timer.</p>

<h4>Controlled guiding</h4>

<p><em>&ldquo;Mind the crater, if you get in, there is no way out.&rdquo;</em></p>

<p>With voice lines from the helmet AI and the mate from the base, the player has constant feedback about beeing on track and <em>doing the right things</em>. Next we had a satellite map that can be shown live on-demand. The satellite itself is visible in the sky by his blinking lights giving the player a constant safety net.</p>

<h4>Sound design</h4>

<p>The atmosphere starts within the intro: heavy breathing. It gives the player an immediate hint what this game is about. The crack sound is synchronized with the title to point out the challenge.</p>

<p>The scene itself starts with an alarm and an AI voice. I used Ableton Live to chain some effects:</p>

<ul>
<li>a raw natural voice recorded with my Shure-SM58</li>
<li>vocoder: make the sound more robotic</li>
<li>chorus: add some warmth and vibrato</li>
<li>high pass filter: low frequencies make AI vocals (think of Siri or Alexa) dirty and feel &ldquo;rumbly&rdquo;, filtering them out help to clearify the voice</li>
<li>duplicate channel and slighetly add an offset to the second (~100ms): add a manual &ldquo;flanger&rdquo; or delayesque sound, this will add some <a href="https://www.youtube.com/watch?v=q5kkwermfs4">glados vibes</a></li>
</ul>

<p>Next to the AI, the mate tries to communicate with the player via radio transmission. With some more effects this radio vibe can be added within godot<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>:</p>

<ul>
<li>again my voice</li>
<li>distortion + limiter, let the vocal clip and lower the volume afterwards down immediately: add a rich palette of overtones known from <a href="https://www.youtube.com/watch?v=DejhGSEu8wk&amp;t=549s">famous space audio logs</a>. This will make the vocals quickly unclear and must be gently tweaked.</li>
<li>band pass filter: cut most of the low frequencies (likewise to the AI) but also some high ones. This will immitate the highly limited bandwith of radio transmissions in space.</li>
</ul>

<p><img src="godot-wild-jam-48_audio_busses.png"/><img src="godot-wild-jam-48_bandpass.png"/></p>

<h4>Audio design</h4>

<p>How does the moon sound like? This is easy in reality. No atmosphere means -&gt; no air were sound can travel -&gt; silence. But cinematographically a sub bass consisting of just a sine wave with sweeping low pass filter and volume adds some depth to the scene. This can be heared in the track <a href="https://soundcloud.com/noise-taeter/welcome-to-the-moon">Welcome to the moon</a>.</p>

<p>When the oxygen tank is almost empty, the more dramatic track <a href="https://soundcloud.com/noise-taeter/wrong-path">Wrong path</a> adds promptly more tension. Starting with gentle and quiet detuned bells, adding a ascending &ldquo;staried&rdquo; loop inspired from the matrix movie soundtrack. It will envolve, adding tension and finally drop when the oxygen tank is empty.</p>

<p>Finally when the player reaches the base in time, some pads with bunch of chained choruses reward the player and the mate speakes without any effect in his natural voice.</p>

<h3>Satellite map with viewports</h3>

<p>The satellite is a model with a camera facing towards the center point of the map. The rotation is made simply by rotating the center point. The camera is then mapped to a viewport on a tablet model that can be toggled by the player.</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">I originally did the effect chain in Ableton Live, too. But since I couldn&rsquo;t work on the jam on the weekend, I did the chain within godot, so I simply could Johannes send raw voice lines via Telegram.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 22 Aug 2022 12:37:13 +0200</pubDate>
    </item>
    <item>
      <title>bye,bye old blog raphaelpour.de</title>
      <link>https://evilcookie.de/byebye-old-blog-raphaelpourde.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>bye bye old blog raphaelpour.de</h1>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">&gt; vim /etc/nginx/nginx.conf <span class="o">&amp;&amp;</span> systemctl restart nginx <span class="c1"># redirect raphaelpour.de to evilcookie.de</span>
</span></span><span class="line"><span class="cl">&gt; <span class="nb">echo</span> <span class="s2">&#34;DROP DATABASE wordpress;&#34;</span> <span class="p">|</span> mysql
</span></span><span class="line"><span class="cl">&gt; rm -rf /var/www/wordpress
</span></span></code></pre>
<p>It was time to let go of my longest running blog so far. Although archive.org dates back
the first occurrence to <a href="https://web.archive.org/web/20160110001415/http://raphaelpour.de/">2016</a>, the
impressum says 2015.</p>

<p>I migrated the imho best posts to <code>$this</code> new blog:</p>

<ul>
<li><a href="saving-goats-with-prolog.html">saving goats with prolog</a></li>
<li><a href="debugging-c-with-gdb.html">debugging c with gdb</a></li>
<li><a href="inside-a-c-float.html">inside a c float</a></li>
</ul>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 01 Aug 2022 19:01:48 +0200</pubDate>
    </item>
    <item>
      <title>Inside a C float</title>
      <link>https://evilcookie.de/inside-a-c-float.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Inside a C float</h1>

<h2>Preface</h2>

<p>This post was originally published in my old blog raphaelpour.de on 12.01.2018.
This was a great introduction of how memory gets intrpreted within a type system
and how to look behind the magic. I&rsquo;ve added the part <a href="#ieee-754-compoents">IEEE 754
components</a>.</p>

<h2>Article</h2>

<p>Handling with floats can  be irritating while it is one of the non-integral datatypes. This means that the displayed value (e.g. via
<code>printf(&quot;%f&quot;,somefloat)</code>)  is different to the one actualy stored in memory. This is caused by <a href="http://ieeexplore.ieee.org/servlet/opac?punumber=2355">IEEE754</a>.</p>

<p>To get the real values we have to go inside the float. A cast wouldn&rsquo;t do the
job, because it would just turn a 3.1415 into 3<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>.
C has a very nice keyword which can help us: <code>union</code>
Instead of casting datatypes, we just map different variables with different datatypes to the exact same memory.</p>

<p>The following four-liner will do the trick for us.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">union</span> <span class="n">floatDbg</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">float</span> <span class="n">f</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">c</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="p">;</span>
</span></span></code></pre>
<p>Now we can access every byte of the float and get the real value. To know what the values are telling us, we would need to know the IEEE754 Algorithm. But that is another story.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">union</span> <span class="n">floatDbg</span> <span class="n">dbg</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">dbg</span><span class="p">.</span><span class="n">f</span> <span class="o">=</span> <span class="mf">13.37</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// decimal output
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">%.2f -&gt; %d %d %d %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">f</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="p">)</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// out: 13.37 -&gt; 133 235 85 65
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// hex output
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">%.2f -&gt; %x %x %x %x</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">f</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// out: 13.37 -&gt; 85 eb 55 41
</span></span></span></code></pre>
<h3>IEEE 754 compnents</h3>

<p>On my little endian machine, we can even get the actual components of the IEE754
float. Bitmasks help to limit the amount of bits we want to map into a struct
field:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="k">typedef</span> <span class="k">union</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">float</span> <span class="n">f</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">c</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kt">unsigned</span> <span class="nl">fraction</span><span class="p">:</span><span class="mi">23</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="kt">unsigned</span> <span class="nl">exponent</span><span class="p">:</span><span class="mi">8</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="kt">unsigned</span> <span class="nl">sign</span><span class="p">:</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="n">floatDbg</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">dump</span><span class="p">(</span><span class="n">floatDbg</span> <span class="n">dbg</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[</span><span class="p">]</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">floatDbg</span> <span class="n">dbg</span><span class="p">,</span><span class="n">dbg2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">dbg</span><span class="p">.</span><span class="n">f</span> <span class="o">=</span> <span class="mf">13.37</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">--[ raw ]--</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">   float: %.2f</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">f</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">   bytes: %02x %02x %02x %02x</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">     bin: %08b %08b %08b %08b</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">--[ iee754 components] --</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">    sign: %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">sign</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">exponent: %d (real=%d)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">exponent</span><span class="o">-</span><span class="mi">127</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">exponent</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">fraction: %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">dbg</span><span class="p">.</span><span class="n">fraction</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/* out:
</span></span></span><span class="line"><span class="cl"><span class="cm"> * --[ raw ]--
</span></span></span><span class="line"><span class="cl"><span class="cm"> *    float: 13.37
</span></span></span><span class="line"><span class="cl"><span class="cm"> *    bytes: 41 55 eb 85
</span></span></span><span class="line"><span class="cl"><span class="cm"> *      bin: 01000001 01010101 11101011 10000101
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 
</span></span></span><span class="line"><span class="cl"><span class="cm"> * --[ iee754 components] --
</span></span></span><span class="line"><span class="cl"><span class="cm"> *     sign: 0
</span></span></span><span class="line"><span class="cl"><span class="cm"> * exponent: 3 (real=130)
</span></span></span><span class="line"><span class="cl"><span class="cm"> * fraction: 5630853
</span></span></span></code></pre>
<div class="footnotes">

<hr>

<ol>
<li id="fn:1">this turns only out to be true if you are living in the <a href="https://en.wikipedia.org/wiki/Indiana_Pi_Bill">us state Indiana</a></li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 27 Jul 2022 15:00:13 +0200</pubDate>
    </item>
    <item>
      <title>debugging c with gdb</title>
      <link>https://evilcookie.de/debugging-c-with-gdb.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Debugging C with gdb</h1>

<h2>Preface</h2>

<p>This post was originally posted in my old blog raphaelpour.de on 06.02.2018. This is probably my most personally used blog post. Once in a while I
need to investigate a coredump that got collected by <code>systemd-coredump</code>. Although the post covers only the tip of the debugging iceberg, it&rsquo;s at least the tip from where you can start walking down.</p>

<h2>Introduction</h2>

<p>As long as the gcc tells you whats wrong (including the <code>-Wall</code> flag) you can at least barely locate the source of the error. What about <em>Segmentation Faults</em> which are hard to detect during compilation time? The <a href="https://www.gnu.org/software/gdb/">GNU Debugger</a> (short gdb) may give you a clue!</p>

<p>Gdb is a command line debugger for investigating binaries. Especially when the binary was compiled with debug information, the debugger can tell us a bit more about its state.</p>

<h2>Starting over with segmentation faults</h2>

<p>For example look at the following code which provokes a segmentation faults by writing to unallocated memory.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdlib.h&gt; </span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;string.h&gt; </span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdio.h&gt; </span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span> 
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">getLyrics</span><span class="p">(</span><span class="kt">char</span><span class="o">*</span> <span class="n">lyricBuffer</span><span class="p">)</span><span class="p">{</span> 
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="kt">char</span> <span class="o">*</span><span class="n">segFaultLyrics</span> <span class="o">=</span> <span class="sa"></span><span class="s">&#34;</span><span class="s">SegFault, SegFault! Whatcha gonna do? Whatcha gonna do when I come for you?</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">memcpy</span><span class="p">(</span><span class="n">lyricBuffer</span><span class="p">,</span> <span class="n">segFaultLyrics</span><span class="p">,</span> <span class="n">strlen</span><span class="p">(</span><span class="n">segFaultLyrics</span><span class="p">)</span><span class="p">)</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="p">}</span> 
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl"><span class="p">{</span> 
</span></span><span class="line"><span class="cl"> <span class="kt">char</span><span class="o">*</span> <span class="n">lyrics</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"> <span class="n">getLyrics</span><span class="p">(</span><span class="n">lyrics</span><span class="p">)</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"> <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">%s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span><span class="n">lyrics</span><span class="p">)</span><span class="p">;</span>                                                                                   
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Let&rsquo;s compile it with gcc and see what happens on execute.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ gcc -Wall debugme1.c -o debugme1
</span></span><span class="line"><span class="cl">$ ./debugme1
</span></span><span class="line"><span class="cl">Segmentation fault <span class="o">(</span>core dumped<span class="o">)</span>
</span></span></code></pre>
<p>Gcc didn&rsquo;t complain anything, even with the <code>-Wall</code> flag.</p>

<p>In order to start over with the gdb, we have to compile our program with debug information. This can be achieved by adding the <code>-g</code> flag to the gcc parameter list.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nv">$gcc</span> -Wall debugme1.c -g -o debugme1
</span></span><span class="line"><span class="cl"><span class="nv">$gdb</span> debugme1
</span></span><span class="line"><span class="cl">Reading symbols from debugme1...done.
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> r
</span></span><span class="line"><span class="cl">Starting program: ~/debugme/debugme1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Program received signal SIGSEGV, Segmentation fault.
</span></span><span class="line"><span class="cl">__memcpy_avx_unaligned <span class="o">(</span><span class="o">)</span> at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:100
</span></span><span class="line"><span class="cl"><span class="m">100</span>     ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S: No such file or directory.
</span></span></code></pre>
<p>As you can see, the gdb tells you which library-function causes the error. What we can&rsquo;t see is the location of this faulty library-function call in our source code.  The No such file or directory error can be ignored with the assumption that our call of this function is wrong and not the original source<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>.
This can be accomplished with the gdb command <code>bt</code> (short for back-trace).</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">(gdb) bt
</span></span><span class="line"><span class="cl">#0 __memcpy_avx_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:100
</span></span><span class="line"><span class="cl">#1 0x000000000040060c in getLyrics (lyricBuffer=0x0) at debugme1.c:8
</span></span><span class="line"><span class="cl">#2 0x000000000040062b in main () at debugme1.c:14
</span></span></code></pre>
<p>The back trace will print the last call stack where the faulty function is on the top. In our example we have to look at the function <code>getLyrics</code> in line 8 which will be the memcpy call.</p>

<p>## Division by zero</p>

<p>Imagine you worked out a fancy formula which solve a certain problem. Especially when you use fractions you have to take care of the range of the input values.
The following code will implement a formula which doesn&rsquo;t care about the input value. The compiler doesn&rsquo;t either.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdio.h&gt;            </span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdlib.h&gt;           </span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>                              
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">magicFormula</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>                             
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a</span><span class="o">/</span><span class="n">b</span><span class="p">;</span>               
</span></span><span class="line"><span class="cl"><span class="p">}</span>                             
</span></span><span class="line"><span class="cl">                              
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span>                    
</span></span><span class="line"><span class="cl"><span class="p">{</span>                             
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">magicFormula</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">printf</span><span class="p">(</span><span class="sa"></span><span class="s">&#34;</span><span class="s">%d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span><span class="n">n</span><span class="p">)</span><span class="p">;</span>         
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>This will cause a <em>floating point exception</em>. This isn&rsquo;t directly a <em>divison-by-zero</em> bug. If you would change the datatype from into float , this operation would be result inf for infinity. But a float  with the value inf can&rsquo;t be casted into an integer. However, we will ask the gdb if he can help us out again.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$gdb debugme2
</span></span><span class="line"><span class="cl">Reading symbols from debugme2...done.
</span></span><span class="line"><span class="cl">(gdb) r
</span></span><span class="line"><span class="cl">Starting program: ~/debugme/debugme2
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Program received signal SIGFPE, Arithmetic exception.
</span></span><span class="line"><span class="cl">0x0000000000400534 in magicFormula (a=1, b=0) at debugme2.c:6
</span></span><span class="line"><span class="cl">6           return a/b;
</span></span></code></pre>
<p>In order to see more than the faulty line, we can use the gdb-command <code>l</code> to list. This will maybe give us the context and a hint why the method magicFormula failed with <code>a=1</code> and <code>b=0</code></p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="p">(</span><span class="n">gdb</span><span class="p">)</span> <span class="n">l</span>
</span></span><span class="line"><span class="cl"><span class="mi">1</span>       <span class="err">#</span><span class="n">include</span> <span class="o">&lt;</span><span class="n">stdio</span><span class="p">.</span><span class="n">h</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="mi">2</span>       <span class="err">#</span><span class="n">include</span> <span class="o">&lt;</span><span class="n">stdlib</span><span class="p">.</span><span class="n">h</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="mi">3</span>
</span></span><span class="line"><span class="cl"><span class="mi">4</span>       <span class="kt">int</span> <span class="n">magicFormula</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="mi">5</span>       <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="mi">6</span>           <span class="k">return</span> <span class="n">a</span><span class="o">/</span><span class="n">b</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="mi">7</span>       <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="mi">8</span>
</span></span><span class="line"><span class="cl"><span class="mi">9</span>       <span class="kt">int</span> <span class="n">main</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="mi">10</span>      <span class="p">{</span>
</span></span></code></pre>
<h2>Tips &lsquo;n&rsquo; Tricks</h2>

<ul>
<li>your application <code>foo</code> needs arguments <code>bar</code> and <code>bbar</code>? Try this: <code>gdb --args foo bar bbar</code></li>
<li>more debug information with the gcc flag <code>-g3</code></li>
<li>there is a console-based gui included in gdb which can be opened with <code>gdb -tui</code></li>
<li><code>strip &lt;binary&gt;</code>  will remove all debug information which the gcc has included into your binary</li>
<li>generate gdb-friendly debug information <a href="https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html">with gcc flag</a>  <code>-ggdb</code></li>
</ul>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">if you think the memcpy is wrong and want to debug it, take a look at <a href="https://stackoverflow.com/a/13979032">this SO Post</a>.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 27 Jul 2022 12:18:58 +0200</pubDate>
    </item>
    <item>
      <title>saving goats with prolog</title>
      <link>https://evilcookie.de/saving-goats-with-prolog.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Saving Goats with Prolog</h1>

<h2>Preface</h2>

<p>This post was originally posted in my old blog raphaelpour.de on 09.02.2018.
Retrospectively this post is a pretty good insight of my artifical intelligence studies back then.</p>

<p><img src="saving-goats-with-prolog_goatprolog.png"/></p>

<p>Spoiler: You might have guessed it already&hellip; you won’t see any real goat in here<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>.
This is about a planning problem and how we can solve it using Prolog. A planning
ploblem could be for example a game or a more or less complex task. You know the
starting and goal state and the rules to go from one state to another, but not if
and how many states are between<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>.</p>

<p>I will describe the problem, break it down to Prolog and solve it with an Iterative Depth Search (IDS).</p>

<h2>Where are the Goats now?</h2>

<p>Okay, first things first: There is only one goat. And this goat can only survive
under specific circumstances.</p>

<p>Imagine you are a ferryman, going from one riverside to the other. Next to some
rickety grandmas (which are taking the ferry almost every day to keep themselves busy)
and a bunch of heavily interested tourists (not interested at all), you were
commissioned to transport three things from riverside A to riverside B:</p>

<ul>
<li>goat</li>
<li>cabbage</li>
<li>wolf</li>
</ul>

<p>Rules:</p>

<ul>
<li>only one thing at a time transportable</li>
<li>goat eats Cabbage</li>
<li>wolf eats Goat</li>
</ul>

<p>How can the ferryman transport all three things from riverside A to B?</p>

<h2>Breakdown of the Problem</h2>

<p>Imagine playing a game which you never played before. The rules are clear but it
might not be clear which strategy is key. The best strategy in the first place
might be guessing or do things in a specific order to gain experience. To make the
things more formal: When I have situation X, which action/move/&hellip; leads me to the
goal situation?</p>

<p>Same thing in Prolog. We can implement the rules, but we need an algorithm which
tries to find a solution. In order to find something, you have to search.
While we have no heuristic (or in our game example: we have no experience) to rank
all current possible actions by shortest distance to the goal, we need an
<em>uninformed search algorithm</em>.</p>

<p>The most effective one is the <em>Iterative Depth Search</em> (IDS). It combines the
positive aspects of the breadth-first- such as the depth-first search and
is therefore optimal (finds always the shortest path).</p>

<p>The search algorithm can walk through a graph where the nodes are states and the
edges are the action/move/&hellip; you have to do in order to go from one state to an other.</p>

<p>In our example, ervery state contains the location of four things: Goat, Cabbage, Wolf
and Ferryman. Every thing can be either on riverside A or B. As a result every state
is a combination of the location of all four things. The Rules are telling us which actions
are allowed and which not.</p>

<p>Let’s imagine how a search graph would look alike (see graphic below). Each node is a state
and each edge is an action.</p>

<p>But this graph has some faulty edges which are not following our rules. Guess which!</p>

<p><img src="saving-goats-with-prolog_goatprolog_graph1.png"/></p>

<p>The following edges are wrong:</p>

<ul>
<li>edge 1: The ferryman is allowed to go alone, but either the goat is eating the cabbage
or the wolf is eating the goat (or both).</li>
<li>edge 3: The wolf is eating the goat.</li>
<li>edge 4: The goat is eating the cabbage.</li>
</ul>

<h2>The Prolog Program</h2>

<p>In order to make use of the search algorithm, we need to put every state into a List describing
the location of each thing: <code>[goat, cabbage, wolf, ferryman]</code>. We start off by describing the
start and goal state:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">start</span><span class="p">(</span><span class="p">[</span><span class="s">a</span><span class="p">,</span><span class="s">a</span><span class="p">,</span><span class="s">a</span><span class="p">,</span><span class="s">a</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="nf">goal</span><span class="p">(</span><span class="p">[</span><span class="s">b</span><span class="p">,</span><span class="s">b</span><span class="p">,</span><span class="s">b</span><span class="p">,</span><span class="s">b</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span></code></pre>
<p>Next we create a transition allowing the ferryman to go alone from riverside A to riverside B.
This is accomplished by only allowing the ferryman variable to change the location, all other
variables have to stay where they are.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">transition0</span><span class="p">(</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="s">a</span><span class="p">]</span><span class="p">,</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="s">b</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span></code></pre>
<p>Let’s add all other transitions.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">transition0</span><span class="p">(</span><span class="p">[</span><span class="s">a</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="s">a</span><span class="p">]</span><span class="p">,</span><span class="p">[</span><span class="s">b</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="s">b</span><span class="p">]</span><span class="p">)</span><span class="p">.</span> 
</span></span><span class="line"><span class="cl"><span class="nf">transition0</span><span class="p">(</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="s">a</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="s">a</span><span class="p">]</span><span class="p">,</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="s">b</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="s">b</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="nf">transition0</span><span class="p">(</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="s">a</span><span class="p">,</span><span class="s">a</span><span class="p">]</span><span class="p">,</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="s">b</span><span class="p">,</span><span class="s">b</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span></code></pre>
<p>This Transition goes only in one direction. Let’s make it symmetric by adding a new
transition predicate.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">transition</span><span class="p">(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">transition0</span><span class="p">(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">)</span><span class="p">;</span><span class="nf">transition0</span><span class="p">(</span><span class="nv">Y</span><span class="p">,</span><span class="nv">X</span><span class="p">)</span><span class="p">.</span>
</span></span></code></pre>
<p>The reason why I called the predicate transition and not rule is that the most rules
are missing. We actually can move from A to B with only on thing at a time, but it is
allowed to keep for example the wolf and the goat alone.
We need to validate each state in order to tell if the transition is allowed or not.
Let’s make a new predicate for the validation and add it later to our symmetric transition.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">valid</span><span class="p">(</span><span class="p">[</span><span class="nv">F</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">F</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="nf">valid</span><span class="p">(</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="k">_</span><span class="p">]</span><span class="p">)</span> <span class="p">:-</span> <span class="nv">G</span> <span class="s">\==</span> <span class="nv">C</span><span class="p">,</span> <span class="nv">G</span> <span class="s">\==</span><span class="nv">W</span><span class="p">.</span>
</span></span></code></pre>
<p>This predicate takes a single state and checks if:</p>

<ul>
<li>The Goat is with the ferryman -&gt; Everything is okay because the wolf doesn’t harm the cabbage</li>
<li>The Goat doesn’t share its location with either wolf or cabbage. We can exclude the ferryman here while we took care of him in the rule above</li>
</ul>

<p>Now we can add the valid predicate to our transition.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">transition</span><span class="p">(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">)</span> <span class="p">:-</span> <span class="p">(</span><span class="nf">transition0</span><span class="p">(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">)</span><span class="p">;</span><span class="nf">transition0</span><span class="p">(</span><span class="nv">Y</span><span class="p">,</span><span class="nv">X</span><span class="p">)</span><span class="p">)</span><span class="p">,</span> <span class="nf">valid</span><span class="p">(</span><span class="nv">X</span><span class="p">)</span><span class="p">,</span><span class="nf">valid</span><span class="p">(</span><span class="nv">Y</span><span class="p">)</span><span class="p">.</span>
</span></span></code></pre>
<h4>Summary</h4>

<ul>
<li>The <code>transition0</code>  Predicate describes which move is allowed from a to b.</li>
<li>The valid  Predicate checks if a single state is legal based on our rules.</li>
</ul>

<p>The transition Predicate uses our <code>transition0</code> in both directions in order to
go from a to b and from b to a. This is possible while Prolog doesn’t have fixed
Input and Output Variables.</p>

<h3>The Search Algorithm (IDS)</h3>

<p>As already mentioned, the Iterative Deepening Search Algorithm fits perfect for our needs.
In order to understand how this search works, I will build it up step by step.</p>

<p>At first we need the depth-first-search on which the IDS is based on.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">ds</span><span class="p">(</span><span class="nv">Node</span><span class="p">,</span> <span class="nv">Goal</span><span class="p">)</span> <span class="p">:-</span>
</span></span><span class="line"><span class="cl">    <span class="nv">Node</span> <span class="o">==</span> <span class="nv">Goal</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">transition</span><span class="p">(</span><span class="nv">Node</span><span class="p">,</span><span class="nv">Neighbour</span><span class="p">)</span><span class="p">,</span> <span class="nf">ds</span><span class="p">(</span><span class="nv">Neighbour</span><span class="p">,</span> <span class="nv">Goal</span><span class="p">)</span><span class="p">.</span>
</span></span></code></pre>
<p>The Depth-First search works with the Back-Tracking feature of Prolog. It goes
into depth until either a Goal is reached or transition  returns false. If the
transition is false, it will go to the previous call of transition and will try
all possible transition s until a goal has been reached or no transitions are
left<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>.</p>

<p>This implementation doesn’t has a kind of a history in order to avoid infinite loops
when the graph has a circle.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">ds</span><span class="p">(</span><span class="nv">Node</span><span class="p">,</span> <span class="nv">Goal</span><span class="p">,</span> <span class="nv">Path</span><span class="p">)</span> <span class="p">:-</span>
</span></span><span class="line"><span class="cl">    <span class="nv">Node</span> <span class="o">==</span> <span class="nv">Goal</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">transition</span><span class="p">(</span><span class="nv">Node</span><span class="p">,</span><span class="nv">Neighbour</span><span class="p">)</span><span class="p">,</span> <span class="o">not</span><span class="p">(</span><span class="nf">member</span><span class="p">(</span><span class="nv">Neighbour</span><span class="p">,</span><span class="nv">Path</span><span class="p">)</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ds</span><span class="p">(</span><span class="nv">Neighbour</span><span class="p">,</span> <span class="nv">Goal</span><span class="p">,</span> <span class="p">[</span><span class="nv">Neighbour</span><span class="p">|</span><span class="nv">Path</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span></code></pre>
<p>Now out Search keeps track of the previous passed nodes and passes no node twice.
Until now, our Search only returns a true or false whenever the goal can be reached
or not. What’s with the path itself? Unfortunately, the path will be deleted when the
search comes back from the recursion. This can be added by using an additional output
variable. This will be filled with a reserved version of our path while the head of
the path is the last move and the last element of the tail our start node.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">ds</span><span class="p">(</span><span class="nv">Node</span><span class="p">,</span> <span class="nv">Goal</span><span class="p">,</span> <span class="nv">Path</span><span class="p">,</span> <span class="nv">ReturnPath</span><span class="p">)</span> <span class="p">:-</span>
</span></span><span class="line"><span class="cl">    <span class="nv">Node</span> <span class="o">==</span> <span class="nv">Goal</span><span class="p">,</span> <span class="nf">reverse</span><span class="p">(</span><span class="nv">Path</span><span class="p">,</span> <span class="nv">ReturnPath</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">transition</span><span class="p">(</span><span class="nv">Node</span><span class="p">,</span><span class="nv">Neighbour</span><span class="p">)</span><span class="p">,</span> <span class="o">not</span><span class="p">(</span><span class="nf">member</span><span class="p">(</span><span class="nv">Neighbour</span><span class="p">,</span><span class="nv">Path</span><span class="p">)</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ds</span><span class="p">(</span><span class="nv">Neighbour</span><span class="p">,</span> <span class="nv">Goal</span><span class="p">,</span> <span class="p">[</span><span class="nv">Neighbour</span><span class="p">|</span><span class="nv">Path</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span></code></pre>
<p>Now we have and uninformed depth-first-search but the <code>i</code> is still missing.
Let&rsquo;s add a loop <code>ids_loop</code> that increases the depth until the goal has been
reached. The loop is solved via recursive call of <code>ids_loop</code> where <code>ids_start</code>
is initializes the loop with the initial depth. Our <code>ds</code> has been extended with
a depth parameter which gets decremented on every recursive call. A depth of
zero will cause the search to return with <code>false</code>.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">ids_core</span><span class="p">(</span><span class="nv">Node</span><span class="p">,</span> <span class="nv">Path</span><span class="p">,</span> <span class="nv">Goal</span><span class="p">,</span> <span class="nv">DepthLimit</span><span class="p">,</span> <span class="nv">ReturnPath</span><span class="p">)</span> <span class="p">:-</span>
</span></span><span class="line"><span class="cl">    <span class="nv">Node</span> <span class="o">==</span> <span class="nv">Goal</span><span class="p">,</span><span class="nf">reverse</span><span class="p">(</span><span class="nv">Path</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">DepthLimit</span><span class="o">&gt;</span><span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">transition</span><span class="p">(</span><span class="nv">Node</span><span class="p">,</span><span class="nv">Neighbour</span><span class="p">)</span><span class="p">,</span><span class="o">not</span><span class="p">(</span><span class="nf">member</span><span class="p">(</span><span class="nv">Neighbour</span><span class="p">,</span><span class="nv">Path</span><span class="p">)</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ids_core</span><span class="p">(</span><span class="nv">Neighbour</span><span class="p">,</span><span class="p">[</span><span class="nv">Neighbour</span><span class="p">|</span><span class="nv">Path</span><span class="p">]</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">DepthLimit</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">ids_loop</span><span class="p">(</span><span class="nv">Start</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">DepthLimit</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span> <span class="p">:-</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ids_core</span><span class="p">(</span><span class="nv">Start</span><span class="p">,</span><span class="p">[</span><span class="nv">Start</span><span class="p">]</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">DepthLimit</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ids_loop</span><span class="p">(</span><span class="nv">Start</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">DepthLimit</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">ids_start</span><span class="p">(</span><span class="nv">Start</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span> <span class="p">:-</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ids_loop</span><span class="p">(</span><span class="nv">Start</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span><span class="p">.</span>
</span></span></code></pre>
<p>This implementation is very generic and can be used not only for rescuing our goat.
For example think about looking for a path from 1 to 5 in the graph below.</p>

<p><img src="saving-goats-with-prolog_goatprolog_graph2.png"/></p>

<h2>Save the Goat (finally)</h2>

<p>Let’s mix all together and save the goat before it starves or get eaten by the bad wolf.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nf">start</span><span class="p">(</span><span class="p">[</span><span class="s">a</span><span class="p">,</span><span class="s">a</span><span class="p">,</span><span class="s">a</span><span class="p">,</span><span class="s">a</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="nf">goal</span><span class="p">(</span><span class="p">[</span><span class="s">b</span><span class="p">,</span><span class="s">b</span><span class="p">,</span><span class="s">b</span><span class="p">,</span><span class="s">b</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">transition0</span><span class="p">(</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="nv">F1</span><span class="p">]</span><span class="p">,</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="nv">F2</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="nf">transition0</span><span class="p">(</span><span class="p">[</span><span class="nv">F1</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="nv">F1</span><span class="p">]</span><span class="p">,</span><span class="p">[</span><span class="nv">F2</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="nv">F2</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="nf">transition0</span><span class="p">(</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">F1</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="nv">F1</span><span class="p">]</span><span class="p">,</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">F2</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="nv">F2</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="nf">transition0</span><span class="p">(</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">F1</span><span class="p">,</span><span class="nv">F1</span><span class="p">]</span><span class="p">,</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">F2</span><span class="p">,</span><span class="nv">F2</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">transition</span><span class="p">(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">)</span> <span class="p">:-</span> <span class="p">(</span><span class="nf">transition0</span><span class="p">(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">)</span><span class="p">;</span><span class="nf">transition0</span><span class="p">(</span><span class="nv">Y</span><span class="p">,</span><span class="nv">X</span><span class="p">)</span><span class="p">)</span><span class="p">,</span> <span class="nf">valid</span><span class="p">(</span><span class="nv">X</span><span class="p">)</span><span class="p">,</span><span class="nf">valid</span><span class="p">(</span><span class="nv">Y</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">valid</span><span class="p">(</span><span class="p">[</span><span class="nv">F</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">F</span><span class="p">]</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="nf">valid</span><span class="p">(</span><span class="p">[</span><span class="nv">G</span><span class="p">,</span><span class="nv">C</span><span class="p">,</span><span class="nv">W</span><span class="p">,</span><span class="k">_</span><span class="p">]</span><span class="p">)</span> <span class="p">:-</span> <span class="nv">G</span> <span class="s">\==</span> <span class="nv">C</span><span class="p">,</span> <span class="nv">G</span> <span class="s">\==</span><span class="nv">W</span><span class="p">.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">% Iterative Depth-Search Algorithm</span>
</span></span><span class="line"><span class="cl"><span class="nf">ids_core</span><span class="p">(</span><span class="nv">Node</span><span class="p">,</span> <span class="nv">Path</span><span class="p">,</span> <span class="nv">Goal</span><span class="p">,</span> <span class="nv">DepthLimit</span><span class="p">,</span> <span class="nv">ReturnPath</span><span class="p">)</span> <span class="p">:-</span>
</span></span><span class="line"><span class="cl">    <span class="nv">Node</span> <span class="o">==</span> <span class="nv">Goal</span><span class="p">,</span><span class="nf">reverse</span><span class="p">(</span><span class="nv">Path</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">transition0</span><span class="p">(</span><span class="nv">Node</span><span class="p">,</span><span class="nv">Neighbour</span><span class="p">)</span><span class="p">,</span><span class="o">not</span><span class="p">(</span><span class="nf">member</span><span class="p">(</span><span class="nv">Neighbour</span><span class="p">,</span><span class="nv">Path</span><span class="p">)</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ids_core</span><span class="p">(</span><span class="nv">Neighbour</span><span class="p">,</span><span class="p">[</span><span class="nv">Node</span><span class="p">|</span><span class="nv">Path</span><span class="p">]</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">DepthLimit</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">ids_loop</span><span class="p">(</span><span class="nv">Start</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">DepthLimit</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span> <span class="p">:-</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ids_core</span><span class="p">(</span><span class="nv">Start</span><span class="p">,</span><span class="p">[</span><span class="nv">Start</span><span class="p">]</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">DepthLimit</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ids_loop</span><span class="p">(</span><span class="nv">Start</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">DepthLimit</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">ids_start</span><span class="p">(</span><span class="nv">Start</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">ids_loop</span><span class="p">(</span><span class="nv">Start</span><span class="p">,</span><span class="nv">Goal</span><span class="p">,</span><span class="nv">ReturnPath</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span><span class="p">.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">save_the_goat</span><span class="p">(</span><span class="p">)</span> <span class="p">:-</span>
</span></span><span class="line"><span class="cl">    <span class="nf">start</span><span class="p">(</span><span class="nv">S</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">goal</span><span class="p">(</span><span class="nv">G</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">ids_start</span><span class="p">(</span><span class="nv">S</span><span class="p">,</span><span class="nv">G</span><span class="p">,</span><span class="nv">R</span><span class="p">)</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nf">write</span><span class="p">(</span><span class="nv">R</span><span class="p">)</span><span class="p">.</span>
</span></span></code></pre>
<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Except in the featured image but I adoptet her from Pixabay</li>

<li id="fn:2">And if there are multiple ways to reach the goal. But this is not important for us. While our approach with the Iterative Deepening Search finds always the shortest way to the goal.</li>

<li id="fn:3">For simplicity, I didn’t made transition  symmetric. This means that the search algorithm can go in both directions. In our example the search can only go from top to down. To be more correct I should’ve added arrows to all edges in Figure 2 to make the graph directional.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Sat, 23 Jul 2022 18:54:31 +0200</pubDate>
    </item>
    <item>
      <title>make-gitlab approve button</title>
      <link>https://evilcookie.de/make-gitlab-approve-button.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>make - gitlab approve button</h1>

<p><img src="make-gitlab-approve-button_approve1.jpg"/>
<img src="make-gitlab-approve-button_approve2.jpg"/></p>

<p>I constructed the gitlab merge-request approve button as 3D model and printed
it. The font is <code>Sourcecode Pro</code>, which I discovered from the public gitlab
using the firefox developer console, but it still looks a bit off to the
original one.</p>

<p>Anyway, it fits nicely into a nerdy developer office.</p>

<h2>Next</h2>

<p>Since the feedback from my colleagues was quite positive, I thought about
printing more gitlab stuff like the green/red pipeline status symbol. Adding a
magnet would turn them into actual whiteboard helpers.</p>

<h2>Update (24.01.2023)</h2>

<p>Now available <a href="https://www.printables.com/model/359925-approve-brick">on printables</a>.</p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 08 Jul 2022 12:24:02 +0200</pubDate>
    </item>
    <item>
      <title>we are developers world congress 2022</title>
      <link>https://evilcookie.de/we-are-developers-world-congress-2022.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>we are developers world congress 2022</h1>

<p>I attended at the <a href="https://www.wearedevelopers.com/world-congress">WeAreDevelopers world
congress</a> 2022 in Berlin.</p>

<p>Some facts:</p>

<ul>
<li>date: 14.06. - 15.06.</li>
<li>speakers: 250</li>
<li>atendees: 8000</li>
<li>regular ticket price 600€</li>
</ul>

<p><strong>Disclaimer:</strong> I&rsquo;m paraphrasing (italic) the speaker based on my notes and memories as best as I can.</p>

<ol>
<li><a href="#cpp">Evolution of C++ - Bjarne Stroustrup</a></li>
<li><a href="#game">We are all part of the game - Joanna Pirker</a></li>
<li><a href="#wolfenstein3d">Wolfenstein 3D Post mortem - John Romero</a></li>
</ol>

<h2>Evolution of C++ - Bjarne Stroustrup<a id='cpp'/></h2>

<p>The inventor of C++ <a href="https://www.stroustrup.com/">himself</a> gave a brief history
of C++, its features and progress over time.</p>

<h3>Low Level abstraction</h3>

<p><em>Bjarne&rsquo;s initial motivation to create C++ was the lack of C&rsquo;s (or any available
language) abstraction while keeping it&rsquo;s
flexibility talking to hardware without unecessary layers. Dynamic memory
without memory management. Someone needs to care about resource: RAII (Resource
acquisition is initialization. A class cares about acquiring a resource
via constructor and releasing it again via destructor, implicitly.</em></p>

<h3>All good engineering relies on feedback</h3>

<p><em>C++ was shaped by its users and use-cases. While its initial purpose was for the probable first network cluster software (wich got never developed), it got attention from bunch of other directions.</em></p>

<p>I conclude &ldquo;Shaphing through feedback&rdquo; from this and would even say that this is true for many more areas of our life. Especially positive feedback (or as AI people might say &ldquo;positive reinforcement&rdquo;) will let us focus on the things that went well. That&rsquo;s one metric I try to measure for private software projects, which make more fun if its useful for someone.</p>

<h3>Make it simple, don&rsquo;t be to clever</h3>

<p>What&rsquo;s called KISS (Keep it simple stupid) today was important back then to
avoid overengineering.</p>

<h3>Compile time optimizations</h3>

<p><em>Anything the compiler can compute, doesn&rsquo;t need to get computed at runtime.
From constant arithmetic expressions to static assertions. The latter has the
goal to outsource error-handling more to the compiler to improve runtime
performance.</em></p>

<h3>Influence</h3>

<p>It was very impressive that the language introduces sophisticated concepts like generics and shaped a whole
world<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. Even if we don&rsquo;t use it, it seems to be anywhere: conceptual and as a
fundament for higher languages or engines.</p>

<h2>We are all part of the game - Joanna Pirker<a name='game'/></h2>

<p><a href="http://jpirker.com/about-johanna/">Joanna Pirker</a></p>

<h3>Physical presence</h3>

<p>_People celebrated birthdays and weddings within <a href="https://en.wikipedia.org/wiki/Animal_Crossing">Animal Crossing</a> during the pandemic<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>. While video converences like skype or zoom let their attendees feel the difference by lack of physical presence, games do. Like in Animal Crossing<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>, there is a physical interactible presence/avatar representing the friend or family member._</p>

<p>Having a family spread across the country, playing games with physical presence can be quite helpful to overcome distance. Especially with my brother I play games like Minecraft, Fortnite, Raft, GTA, Borderlands, Risk of rain, No mans sky.</p>

<p>As long as this doesn&rsquo;t replace real interaction, this is a good thing in my opinion.</p>

<h2>Wolfenstein 3D Post mortem - John Romero<a name='wolfenstein3d'></a></h2>

<p><a href="https://romero.com/">John Romero</a> is a founder of the famous <a href="https://idsoftware.com">id software</a> game studio from 1991.</p>

<h3>Debugging</h3>

<p><em>There were no debugger around at that time, so the cycle was: making a small code change, test game, repeat. With Assembler and C.</em></p>

<p>Its amazing how this was even possible. They made their own engine and built a dozen of games per year, mostly two at the same time, with not more than six people. Debugging a game engine without debugger sounds like huge pain to me.
Maybe the whole automation, meta-language and tooling thing to accelerate the feedback loop on debugging prevents a developer to evolve their focus and &ldquo;stamina&rdquo;. Like how long do you follow the path down the rabbit hole when things go wrong? If you&rsquo;re already familiar with the assembler-hell, maybe nothing can stop you.
Nowadays I don&rsquo;t have any clue about processor registers in memory dumps and I primarily evaluate a more high level way of debug something than get my hands dirty. Maybe I should&hellip;</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Go introduces generics this year with 1.18</li>

<li id="fn:2">See <a href="https://www.washingtonpost.com/video-games/2020/04/02/animal-crossing-wedding-coronavirus/">Washington Post: The pandemic canceled their wedding. So they held it in Animal Crossing.</a></li>

<li id="fn:3">or in my case GTA 5</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Thu, 16 Jun 2022 23:38:54 +0200</pubDate>
    </item>
    <item>
      <title>blog-update-v0.3.0</title>
      <link>https://evilcookie.de/blog-update-v030.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>blog update: v0.3.0</h1>

<p><a href="https://github.com/RaphaelPour/blogctl/releases/tag/v0.3.0">Blogctl v0.3.0</a> is out!</p>

<ul>
<li>CI release automation</li>
<li>navigation in posts (next, previous, home)</li>
<li>syntax highlighting</li>
</ul>

<h2>CI release automation</h2>

<p><code>blogctl</code> can now be released pretty straight forward:</p>

<ul>
<li>add latest change to changelog<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>: <code>task cangelog</code></li>
<li>bump version and release it: <code>task release</code></li>
</ul>

<p>That&rsquo;s it! A <a href="https://github.com/RaphaelPour/blogctl/blob/master/.github/workflows/blogctl.yml#L32">tag pipeline will start</a> and create <a href="https://github.com/RaphaelPour/blogctl/releases/tag/v0.3.0">a new release</a> with 64bit binaries for linux and mac<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>.</p>

<h2>Navigation</h2>

<p>See blog article <a href="https://evilcookie.de/blog-update---navigation.html">blog update:
navigation</a>.</p>

<h2>Syntax highlighting</h2>

<p>Code blocks are now syntax highlighted<sup class="footnote-ref" id="fnref:3"><a href="#fn:3">3</a></sup>. I decided to use a
more subtle, monochrome style only to keep focus. We used the lib
<a href="https://github.com/alecthomas/chroma">chroma</a> which supports a lot of languages
and can be configured via CSS. This feature also <a href="https://github.com/RaphaelPour/blogctl/blob/master/cmd/render.go#L301">adds some clutter to the html
template</a> where the CSS needs to be included. It&rsquo;s planned to clean this up and
outsource the stylesheet to the highlight package where it belongs to.</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">I use <a href="https://github.com/MarkusFreitag/changelogger">changelogger</a> to add entries, bump versions and render summaries interactively.<br></li>

<li id="fn:2">Windows is not included as the interactive part of blogctl requires a unix shell to open a terminal editor configured via environment variables <code>VISUAL</code> or <code>EDITOR</code> (thanks to <a href="https://github.com/MarkusFreitag/changelogger/blob/master/pkg/editor/editor.go">changelogger</a> for that trick).<br></li>

<li id="fn:3">Thanks to <a href="https://github.com/Tch1b0">Tch1b0</a> for the contribution!</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Sun, 27 Mar 2022 09:43:35 +0200</pubDate>
    </item>
    <item>
      <title>clt 2022 - storage migration: schnell und einfach</title>
      <link>https://evilcookie.de/clt-2022---storage-migration-schnell-und-einfach.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>clt 2022 - storage migration: schnell und einfach</h1>

<p>I just did my first public german talk <a href="https://chemnitzer.linux-tage.de/2022/en/programm/beitrag/147">Storage Migration: Schnell und
einfach</a> about
transferring local storage fast and simple, last Saturday.</p>

<p>The lecture got recorded and I&rsquo;ll update this post with a link once published.</p>

<h2>Some data</h2>

<ul>
<li>~60 visitors</li>
<li>presentation took ~30 min.</li>
<li>interview took another ~10 min.</li>
<li><a href="https://chemnitzer.linux-tage.de/2022/media/video/147.mp4">recording</a></li>
<li><a href="https://chemnitzer.linux-tage.de/2022/media/programm/folien/147.pdf">slides</a></li>
<li><a href="https://chemnitzer.linux-tage.de/2022/media/programm/shortpaper/147.pdf">shortpaper</a></li>
<li><a href="https://chemnitzer.linux-tage.de/2022/de/programm/beitrag/147">clt site</a></li>
<li><del><a href="https://pad.live.linux-tage.de/HIq15alBRhqJMBR2dUlLCQ#">pad</a></del> dead</li>
<li><a href="https://chemnitzer.linux-tage.de/2022/en/programm/beitrag/bewertung/147/0ca2a2c40a0256ea7677cae468a687db">rating</a>
(1=bad..5=excellent)

<ul>
<li>17 ratings</li>
<li>structure and intelligibility: 4.5882352941176.round(1) = 4.5</li>
<li>correspondence with announcement: 4.5882352941176.round(1) = 4.5</li>
</ul></li>
</ul>

<h2>Summary</h2>

<p>We<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> optimized the migration of a 120GB disk with 50% used data
from roughly eight to about one minute. This could be accomplished by replacing
the former solution <a href="https://www.maier-komor.de/mbuffer.html">mbuffer</a> with our
self made one. A HTTP server/client simplifies the connection handling by natively
supporting encryption via TLS such as parallelism via concurrent connections. As
our local storage is a <a href="https://man7.org/linux/man-pages/man7/lvmthin.7.html">thin provisioned
lv</a>, we could use a block map to only
transfer used data.</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Cloud services team at <a href="https://www.hetzner.com/cloud">Hetzner Online</a></li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 14 Mar 2022 13:47:05 +0100</pubDate>
    </item>
    <item>
      <title>blog update about me</title>
      <link>https://evilcookie.de/blog-update-about-me.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>blog update: about me</h1>

<p><img src="blog-update-about-me_me.png"/></p>

<p>The confirmation of my <a href="https://chemnitzer.linux-tage.de/2022/de/programm/beitrag/147">CLT 2022
lecture</a>
triggered me to add more &lsquo;about me&rsquo; to my blog.</p>

<p>Originally I wanted to add static-site support to add a separate &lsquo;about me&rsquo;
page, but this would need a more sophisticated concept. So my intermediate solution was to
just hard code a banner with a short introduction.</p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 25 Feb 2022 12:36:54 +0100</pubDate>
    </item>
    <item>
      <title>godot wild jam 42 - the ancient game of ur</title>
      <link>https://evilcookie.de/godot-wild-jam-42---the-ancient-game-of-ur.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>godot wild jam 42 - the ancient game of ur</h1>

<p>My mates<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> and I participated at the <a href="https://itch.io/jam/godot-wild-jam-42">42. Godot Wild
Jam</a> with our submission <a href="https://evilc00kie.itch.io/the-ancient-game-of-ur">The ancient
Game of Ur</a>.</p>

<p>The theme was <em>Ancient</em> and we decided to interpret the &lsquo;oldest known&rsquo; board
game <a href="https://en.wikipedia.org/wiki/Royal_Game_of_Ur"><em>Royal game of Ur</em></a>. We
decided to do a 3D game playing against an AI.</p>

<p>To fulfill the wildcard <em>Mom I&rsquo;m on TV</em><sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>, we added four AI&rsquo;s
with different strategies representing us developers:</p>

<ul>
<li>tch1bo: kicks out opponent whenever possible</li>
<li>kjarrigan:

<ul>
<li>1st: moves tokens to safe space at the end of the board, for tokens
positioned after the middle/shared special field</li>
<li>2nd: add as much tokens to the board as possible</li>
</ul></li>
<li>jOBraun:

<ul>
<li>1st: move token away from enemy that could probably kick the token out</li>
<li>2nd: move new token in if there are less than 3 on the board</li>
</ul></li>
<li>evilcookie:

<ul>
<li>1st: move to special field</li>
<li>2st: stay on middle/shared special fields as long as possible</li>
<li>3rd: try to kick out opponent&rsquo;s tokens in the first half the field</li>
</ul></li>
</ul>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1"><a href="https://github.com/Tch1b0">Johannes</a>, <a href="https://github.com/Kjarrigan">Holger</a> and <a href="https://github.com/j0braun">John</a><br></li>

<li id="fn:2">&ldquo;Shoehorn in developer cameos&rdquo;</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 22 Feb 2022 13:03:56 +0100</pubDate>
    </item>
    <item>
      <title>hcloud-ruby v1.0.3</title>
      <link>https://evilcookie.de/hcloud-ruby-v103.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>hcloud-ruby v1.0.3</h1>

<p>I&rsquo;m now contributing and maintaining the <a href="https://rubygems.org/gems/hcloud">ruby gem <code>hcloud</code></a>, a client for the
<a href="https://docs.hetzner.cloud/">Hetzner Cloud API</a>. As a first &lsquo;official act&rsquo;, we<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> tidied the repo up a bit and
released <a href="https://github.com/tonobo/hcloud-ruby/tree/v1.0.3">v1.0.3</a>.</p>

<h2>Changes</h2>

<ul>
<li>set up a working CI, shifting from travis<sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup> to <a href="https://github.com/tonobo/hcloud-ruby/blob/v1.0.3/.github/workflows/ruby.yml">github actions</a></li>
<li>support ruby 3.0+3.1</li>
</ul>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">credits to <a href="https://github.com/Kjarrigan">Holger</a></li>

<li id="fn:2"><a href="https://news.ycombinator.com/item?id=25338983">https://news.ycombinator.com/item?id=25338983</a><br></li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Thu, 17 Feb 2022 16:22:12 +0100</pubDate>
    </item>
    <item>
      <title>git: split commits</title>
      <link>https://evilcookie.de/git-split-commits.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>git: split commits</h1>

<p>Is that branch commit list familiar to you?</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">pick a70ebde big commit with major feature update
</span></span><span class="line"><span class="cl">pick e561140 minor change
</span></span><span class="line"><span class="cl">pick e3dfbbe minor change
</span></span><span class="line"><span class="cl">pick 5648ef4 minor change
</span></span></code></pre>
<p>That one big commit <code>a70ebde</code> that should better be several smaller ones?</p>

<ol>
<li>edit commit via rebase:

<ul>
<li><code>git rebase -i &lt;main branch&gt;</code></li>
<li>replace <code>pick</code> with <code>edit</code> or <code>e</code> of the big commit</li>
</ul></li>
<li>reset commit (softly!) via <code>git reset HEAD^</code></li>
<li>commit everything separately</li>
<li>finish rebase: <code>git rebase --continue</code></li>
</ol>

<p>If you get stuck in any stage, just abort the process with <code>git rebase --abort</code>.</p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 11 Feb 2022 12:21:41 +0100</pubDate>
    </item>
    <item>
      <title>blog update - navigation</title>
      <link>https://evilcookie.de/blog-update---navigation.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>blog update: navigation</h1>

<p><a href="https://github.com/RaphaelPour/blogctl"><code>Blogctl</code></a> now renders navigation links per post:</p>

<ul>
<li>previous post: <code>&lt;</code></li>
<li><code>up</code> to the index</li>
<li>next post: <code>&gt;</code></li>
</ul>

<h2>Motivation</h2>

<p>Although I&rsquo;ve added <a href="https://github.com/RaphaelPour/blogctl/issues/33">the feature
request</a> over a year ago, now
was the right time to implement it.</p>

<p>Since a lot of projects vanish or get stale due to lack of motivation, I want to
develop blogctl and my blog differently.</p>

<p>Like if ideas were soap bubbles, growing bigger if the idea gets more useful or generates attention.
When they&rsquo;re big enough and pop, the right time for implementation has arrived. If they&rsquo;re flying out
of sight without popping, it might be better to wait or drop them entirely.</p>

<p>I try to make sure, with this strategy, that only <em>relevant</em> features get my
attention/motivation.</p>

<p>The <em>pop</em> of this feature actually happens due to <a href="https://github.com/RaphaelPour/blogctl/issues/33#issuecomment-1017966739">Robert&rsquo;s
+1</a>.</p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 26 Jan 2022 12:47:44 +0100</pubDate>
    </item>
    <item>
      <title>aoc21-9 3d print of cave height map</title>
      <link>https://evilcookie.de/aoc21-9-3d-print-of-cave-height-map.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>AoC 2021 day 9 - 3D print of cave height map</h1>

<p>After solving the <a href="https://adventofcode.com/2021/day/9">puzzle of day 9</a> about a
cave with basins and heights from 0 to 9, we<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup> thought about 3D printing the input as height map.</p>

<h2>Go program</h2>

<p>I generated an <a href="https://en.wikipedia.org/wiki/STL_(file_format)">STL model</a>
using the puzzle input as list of lines:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">renderSTL</span><span class="p">(</span><span class="nx">input</span> <span class="p">[</span><span class="p">]</span><span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">filename</span> <span class="o">:=</span> <span class="s">&#34;day09.stl&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// list of all generated boxes
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">boxes</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="p">[</span><span class="p">]</span><span class="nx">sdf</span><span class="p">.</span><span class="nx">SDF3</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// base plate on which the height 0 begins 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">plate2d</span> <span class="o">:=</span> <span class="nx">sdf</span><span class="p">.</span><span class="nf">Box2D</span><span class="p">(</span><span class="nx">sdf</span><span class="p">.</span><span class="nx">V2</span><span class="p">{</span><span class="nb">float64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="nx">input</span><span class="p">)</span><span class="p">)</span><span class="p">,</span> <span class="nb">float64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="nx">input</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">)</span><span class="p">)</span><span class="p">}</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">plate3d</span> <span class="o">:=</span> <span class="nx">sdf</span><span class="p">.</span><span class="nf">Extrude3D</span><span class="p">(</span><span class="nx">plate2d</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// Move plate completely to the positive space. Initially the center of the
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// plate is positioned at the origin.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">plateM</span> <span class="o">:=</span> <span class="nx">sdf</span><span class="p">.</span><span class="nf">Translate3d</span><span class="p">(</span><span class="nx">sdf</span><span class="p">.</span><span class="nx">V3</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">float64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="nx">input</span><span class="p">)</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nb">float64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="nx">input</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="p">)</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">boxes</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">boxes</span><span class="p">,</span> <span class="nx">sdf</span><span class="p">.</span><span class="nf">Transform3D</span><span class="p">(</span><span class="nx">plate3d</span><span class="p">,</span> <span class="nx">plateM</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">row</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">input</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="nx">x</span><span class="p">,</span> <span class="nx">cell</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">row</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="nx">cell</span> <span class="o">==</span> <span class="sc">&#39;0&#39;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">continue</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="nx">num</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">strconv</span><span class="p">.</span><span class="nf">Atoi</span><span class="p">(</span><span class="nb">string</span><span class="p">(</span><span class="nx">cell</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;error converting %d\n&#34;</span><span class="p">,</span> <span class="nx">cell</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="nx">box2d</span> <span class="o">:=</span> <span class="nx">sdf</span><span class="p">.</span><span class="nf">Box2D</span><span class="p">(</span><span class="nx">sdf</span><span class="p">.</span><span class="nx">V2</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">}</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// add one so level 0 has one unit
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="nx">height</span> <span class="o">:=</span> <span class="nb">float64</span><span class="p">(</span><span class="nx">num</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="nx">box3d</span> <span class="o">:=</span> <span class="nx">sdf</span><span class="p">.</span><span class="nf">Extrude3D</span><span class="p">(</span><span class="nx">box2d</span><span class="p">,</span> <span class="nx">height</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="nx">m</span> <span class="o">:=</span> <span class="nx">sdf</span><span class="p">.</span><span class="nf">Translate3d</span><span class="p">(</span><span class="nx">sdf</span><span class="p">.</span><span class="nx">V3</span><span class="p">{</span><span class="nb">float64</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span><span class="p">,</span> <span class="nb">float64</span><span class="p">(</span><span class="nx">y</span><span class="p">)</span><span class="p">,</span> <span class="nx">height</span> <span class="o">/</span> <span class="mi">2</span><span class="p">}</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="nx">boxes</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">boxes</span><span class="p">,</span> <span class="nx">sdf</span><span class="p">.</span><span class="nf">Transform3D</span><span class="p">(</span><span class="nx">box3d</span><span class="p">,</span> <span class="nx">m</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;generated %d boxes\n&#34;</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="nx">boxes</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">start</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">render</span><span class="p">.</span><span class="nf">RenderSTL</span><span class="p">(</span><span class="nx">sdf</span><span class="p">.</span><span class="nf">Union3D</span><span class="p">(</span><span class="nx">boxes</span><span class="o">...</span><span class="p">)</span><span class="p">,</span> <span class="mi">400</span><span class="p">,</span> <span class="nx">filename</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;needed %s\n&#34;</span><span class="p">,</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Since</span><span class="p">(</span><span class="nx">start</span><span class="p">)</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p><img src="aoc21-9-3d-print-of-cave-height-map_slicer.jpg"/></p>

<h2>Impressions</h2>

<p><img src="aoc21-9-3d-print-of-cave-height-map_result1.jpg"/></p>

<p><img src="aoc21-9-3d-print-of-cave-height-map_result2.jpg"/></p>

<p><img src="aoc21-9-3d-print-of-cave-height-map_result3.jpg"/></p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">credits to <a href="https://github.com/MarkusFreitag">Markus</a></li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 14 Jan 2022 12:46:28 +0100</pubDate>
    </item>
    <item>
      <title>blog update: image support</title>
      <link>https://evilcookie.de/blog-update-image-support.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>blog update: image support</h1>

<p><img src="blog-update-image-support_test.png"/></p>

<p>blogctl now supports images.</p>

<h2>Concept</h2>

<p>Images can be placed inside the post folder and embedded via the <code>IMAGE(&lt;filename&gt;)</code> tag.
The renderer automatically:</p>

<ol>
<li>converts all tags to html</li>
<li>copies the images to the output directory</li>
<li>adds the post title as suffix to the filename.</li>
</ol>

<p>Last one is needed to avoid naming conflicts, having duplicate file names across different
posts<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. Images that aren&rsquo;t referenced, get ignored. The tag helps me to avoid remembering the right path or parsing markdown/html to
adjust the final path.</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">The output directory is flat and has no subdirectories.</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Thu, 13 Jan 2022 22:37:29 +0100</pubDate>
    </item>
    <item>
      <title>firefox: disable download dialog delay</title>
      <link>https://evilcookie.de/firefox-disable-download-dialog-delay.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>firefox: disable download dialog delay</h1>

<p>When downloading files with firefox, the ok button of the file-dialog stays
disabled for a few seconds. This bugged me a dozen of times. I looked
around the config and found a &lsquo;solution&rsquo;:</p>

<ol>
<li>goto <code>about:config</code></li>
<li>set <code>security.dialog_enable_delay</code> to <code>0</code></li>
</ol>

<h2>Downside</h2>

<p>On researching about the config value, it&rsquo;s existing must have a purpose
(right?), I stumbled accross this
post about <a href="https://www.squarefree.com/2004/07/01/race-conditions-in-security-dialogs/">Race conditions in security dialogs</a>
which stated:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">[...] the attack involves convincing the user to double-click a certain spot on
</span></span><span class="line"><span class="cl">the screen [...] where the &#39;Yes&#39; button will appear. The first click triggers
</span></span><span class="line"><span class="cl">the dialog; the second click lands on the &#39;Yes&#39; button.
</span></span></code></pre>
<p>Firefox&rsquo;s delay is <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=162020">their
fix</a> to the stated security
issue<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>.</p>

<h2>Fix</h2>

<p>I set the delay to <code>500</code> as a compromise.</p>

<p>year&hellip;</p>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">WOHA! The issue was filed 19 yrs ago! I went to elementary school that</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 06 Oct 2021 13:41:53 +0200</pubDate>
    </item>
    <item>
      <title>blog update: rss feed</title>
      <link>https://evilcookie.de/blog-update-rss-feed.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>blog update: rss feed</h1>

<p>Blogctl now <a href="https://github.com/RaphaelPour/blogctl/pull/37/commits/d9bbf469e1ab948752ff924f990873bdd11adc9c">generates an rss feed</a> along with the site.</p>

<h2>Motivation</h2>

<p>Since I started to read <a href="https://news.ycombinator.com/">HackerNews</a> on a daily basis, I found a bunch of
blogger that I wanted to keep track of without polling. RSS seemed the right solution for this type of
problem. I use the firefox extension <a href="https://addons.mozilla.org/en-US/firefox/addon/feedbroreader/">feedbro</a> to manage and read my feeds<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>.</p>

<p>This worked out quite well so far. Why not providing my own feed?</p>

<h2>Technical details</h2>

<p>The go package <a href="https://github.com/gorilla/feeds">gorilla/feeds</a> provides an
easy generator for RSS, atom and json.</p>

<ul>
<li><a href="http://antirez.com">Antirez</a>: creator of redis</li>
<li><a href="https://www.brendangregg.com/blog/index.html">Brendan Gregg</a>: Performance engineer currently working at Netflix</li>
<li><a href="https://go.dev/blog/">Go blog</a></li>
<li><a href="https://0pointer.net/blog/">Poettering</a>: creator of systemd</li>
<li><a href="https://xkcd.com/">xkcd</a>: comics about math, computer science and science in general</li>
<li><a href="https://www.monkeyuser.com/">MoneyUser</a>: comics about software development</li>
</ul>

<div class="footnotes">

<hr>

<ol>
<li id="fn:1">Non-exhaustive blog recommendations:</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 06 Oct 2021 10:52:03 +0200</pubDate>
    </item>
    <item>
      <title>Bad practice: busy waiting</title>
      <link>https://evilcookie.de/bad-practice-busy-waiting.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>bad practice: busy-waiting</h1>

<p>Busy-waiting is one of the easiest ways of exhausting a cpu<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="kc">true</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* complex logic */</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>What looks like an obvious bad construct one would never do by accident is often
introduced on waiting for a resource or state change. One common place where such constructs are used
is on reconnecting to a service.</p>

<h2>Analyze</h2>

<p>Use <code>top</code>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">PID     USER       PR   NI VIRT      RES    SHR S %CPU    %MEM  TIME+   COMMAND
</span></span><span class="line"><span class="cl">1237306 evilcookie 20   0  702424    936    644 R 100.3   0.0   0:59.39 busywaiting      
</span></span></code></pre>
<p>The process has a load of one or higher.</p>

<h2>Solutions</h2>

<p>A general solution for busy-waiting is telling the CPU to do something else for
some time using the syscall <code>sleep</code><sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="s">&#34;time&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="kc">true</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* complex logic */</span>
</span></span><span class="line"><span class="cl">    <span class="nx">time</span><span class="p">.</span><span class="nf">Sleep</span><span class="p">(</span><span class="mi">1</span> <span class="o">*</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Millisecond</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Sleeping one millisecond is enough to make the process barely obervable:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">PID     USER      PR   NI VIRT      RES    SHR S %CPU  %MEM  TIME+   COMMAND
</span></span><span class="line"><span class="cl">1242442 rpour     20   0  702476   1340    840 S 8.6   0.0   0:01.05 busywaiting
</span></span></code></pre>
<div class="footnotes">

<hr>

<ol>
<li id="fn:1">all examples are written in golang</li>

<li id="fn:2"><a href="https://man7.org/linux/man-pages/man3/sleep.3.html">sleep (3)</a>: &ldquo;On Linux, sleep() is implemented via <a href="https://man7.org/linux/man-pages/man2/nanosleep.2.html">nanosleep(2)</a>.&rdquo;</li>
</ol>

</div>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Fri, 09 Jul 2021 13:13:03 +0200</pubDate>
    </item>
    <item>
      <title>Read this blog with emacs</title>
      <link>https://evilcookie.de/read-this-blog-with-emacs.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Read this blog with emacs</h1>

<ol>
<li><a href="https://www.gnu.org/software/emacs/download.html">Download and install
emacs</a></li>
<li>start emacs</li>
<li>press <code>meta+x</code> where meta may either ctrl or alt</li>
<li>type <code>eww</code></li>
<li>type <code>evilcookie.de</code></li>
<li>hit <code>return</code></li>
<li>enjoy the blog:

<ul>
<li>navigate: arrow keys</li>
<li>visit links: <code>return</code></li>
<li>go back: <code>l</code></li>
</ul></li>
</ol>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Wed, 26 May 2021 12:53:08 +0200</pubDate>
    </item>
    <item>
      <title>--version always</title>
      <link>https://evilcookie.de/--version-always.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>&ndash;version always</h1>

<p><em>Am I in the matrix?</em></p>

<p>Which sounds like a quote is the result of hours testing and debugging with development releases.
When things get messy and intransparent, it&rsquo;s always good to have a <code>--version</code> printing some build information. Where <em>build information</em> is defined as date and version in this post. Since version control is a industry standard, the last commit sha can be used as version if no other version system is used.</p>

<p>Bonus:</p>

<ul>
<li>Log output of <code>--version</code> directly on every start: When a log lives longer than the version of the corresponding binary, it&rsquo;s easier for error tracing.</li>
<li>Monitor deployed version: Having a lot of servers running different versions of a binary, it becomes easier to export the version using the version-flag.</li>
<li>Distinguish binaries: Having multiple version of a binary at ones, it&rsquo;s easier to distinguish them by version/date.</li>
</ul>

<h3>Contents</h3>

<ul>
<li><a href="#example">Example</a>

<ul>
<li><a href="#linux">Linux variant</a></li>
<li><a href="#others">Others</a></li>
</ul></li>
<li><a href="#implementation">Implementation</a>

<ul>
<li><a href="#go">Go</a></li>
<li><a href="#c">C</a></li>
</ul></li>
<li><a href="#ideas">Further ideas</a></li>
</ul>

<h2>Example<a name='example'></h2>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ ./blogctl --version
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">BuildVersion:  v0.1.3-10-ge84a71f
</span></span><span class="line"><span class="cl">BuildDate:  2020-12-05T17:17:56+0100
</span></span></code></pre><pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ ./femto --version
</span></span><span class="line"><span class="cl">BuildDate: 2020-09-16T15:08:11+0200
</span></span><span class="line"><span class="cl">BuildVersion: v0.4.0-3-g8a901a5
</span></span></code></pre>
<h3>Linux variant<a name='linux'></h3>

<p>The linux variant includes a subset of:</p>

<ul>
<li>name</li>
<li>package</li>
<li>version</li>
<li>target distro</li>
<li>target distro version</li>
<li>license</li>
<li>author</li>
</ul>

<p>Like <code>gcc</code> or <code>bash</code>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ gcc --version
</span></span><span class="line"><span class="cl">gcc <span class="o">(</span>GCC<span class="o">)</span> 10.2.1 <span class="m">20201125</span> <span class="o">(</span>Red Hat 10.2.1-9<span class="o">)</span>
</span></span><span class="line"><span class="cl">Copyright <span class="o">(</span>C<span class="o">)</span> <span class="m">2020</span> Free Software Foundation, Inc.
</span></span><span class="line"><span class="cl">This is free software<span class="p">;</span> see the <span class="nb">source</span> <span class="k">for</span> copying conditions.  There is NO
</span></span><span class="line"><span class="cl">warranty<span class="p">;</span> not even <span class="k">for</span> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
</span></span></code></pre><pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ bash --version
</span></span><span class="line"><span class="cl">GNU bash, version 5.0.17<span class="o">(</span>1<span class="o">)</span>-release <span class="o">(</span>x86_64-pc-linux-gnu<span class="o">)</span>
</span></span><span class="line"><span class="cl">Copyright <span class="o">(</span>C<span class="o">)</span> <span class="m">2019</span> Free Software Foundation, Inc.
</span></span><span class="line"><span class="cl">License GPLv3+: GNU GPL version <span class="m">3</span> or later &lt;http://gnu.org/licenses/gpl.html&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This is free software<span class="p">;</span> you are free to change and redistribute it.
</span></span><span class="line"><span class="cl">There is NO WARRANTY, to the extent permitted by law.
</span></span></code></pre><pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ md5sum --version
</span></span><span class="line"><span class="cl">md5sum <span class="o">(</span>GNU coreutils<span class="o">)</span> 8.30
</span></span><span class="line"><span class="cl">Copyright <span class="o">(</span>C<span class="o">)</span> <span class="m">2018</span> Free Software Foundation, Inc.
</span></span><span class="line"><span class="cl">License GPLv3+: GNU GPL version <span class="m">3</span> or later &lt;https://gnu.org/licenses/gpl.html&gt;.
</span></span><span class="line"><span class="cl">This is free software: you are free to change and redistribute it.
</span></span><span class="line"><span class="cl">There is NO WARRANTY, to the extent permitted by law.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Written by Ulrich Drepper, Scott Miller, and David Madore.
</span></span></code></pre>
<h3>Others<a name='others'></h3>

<p>Docker with version and build hash:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ docker --version
</span></span><span class="line"><span class="cl">Docker version 19.03.12, build 48a66213fe
</span></span></code></pre>
<p>Gpg which looks like the <a href="#linux">linux variant</a> but with all supported algorithms on top:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ gpg --version
</span></span><span class="line"><span class="cl">gpg <span class="o">(</span>GnuPG<span class="o">)</span> 2.2.19
</span></span><span class="line"><span class="cl">libgcrypt 1.8.5
</span></span><span class="line"><span class="cl">Copyright <span class="o">(</span>C<span class="o">)</span> <span class="m">2019</span> Free Software Foundation, Inc.
</span></span><span class="line"><span class="cl">License GPLv3+: GNU GPL version <span class="m">3</span> or later &lt;https://gnu.org/licenses/gpl.html&gt;
</span></span><span class="line"><span class="cl">This is free software: you are free to change and redistribute it.
</span></span><span class="line"><span class="cl">There is NO WARRANTY, to the extent permitted by law.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Home: /root/.gnupg
</span></span><span class="line"><span class="cl">Supported algorithms:
</span></span><span class="line"><span class="cl">Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
</span></span><span class="line"><span class="cl">Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
</span></span><span class="line"><span class="cl">        CAMELLIA128, CAMELLIA192, CAMELLIA256
</span></span><span class="line"><span class="cl">Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
</span></span><span class="line"><span class="cl">Compression: Uncompressed, ZIP, ZLIB, BZIP2
</span></span></code></pre>
<p>Vim with its verbose output:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">$ vim --version
</span></span><span class="line"><span class="cl">VIM - Vi IMproved 8.1 <span class="o">(</span><span class="m">2018</span> May 18, compiled Apr <span class="m">15</span> <span class="m">2020</span> 06:40:31<span class="o">)</span>
</span></span><span class="line"><span class="cl">Included patches: 1-2269
</span></span><span class="line"><span class="cl">Modified by team+vim@tracker.debian.org
</span></span><span class="line"><span class="cl">Compiled by team+vim@tracker.debian.org
</span></span><span class="line"><span class="cl">Huge version without GUI.  Features included <span class="o">(</span>+<span class="o">)</span> or not <span class="o">(</span>-<span class="o">)</span>:
</span></span><span class="line"><span class="cl">+acl               -farsi             -mouse_sysmouse    -tag_any_white
</span></span><span class="line"><span class="cl">+arabic            +file_in_path      +mouse_urxvt       -tcl
</span></span><span class="line"><span class="cl">+autocmd           +find_in_path      +mouse_xterm       +termguicolors
</span></span><span class="line"><span class="cl">+autochdir         +float             +multi_byte        +terminal
</span></span><span class="line"><span class="cl">-autoservername    +folding           +multi_lang        +terminfo
</span></span><span class="line"><span class="cl">-balloon_eval      -footer            -mzscheme          +termresponse
</span></span><span class="line"><span class="cl">+balloon_eval_term +fork<span class="o">(</span><span class="o">)</span>            +netbeans_intg     +textobjects
</span></span><span class="line"><span class="cl">-browse            +gettext           +num64             +textprop
</span></span><span class="line"><span class="cl">++builtin_terms    -hangul_input      +packages          +timers
</span></span><span class="line"><span class="cl">+byte_offset       +iconv             +path_extra        +title
</span></span><span class="line"><span class="cl">+channel           +insert_expand     -perl              -toolbar
</span></span><span class="line"><span class="cl">+cindent           +job               +persistent_undo   +user_commands
</span></span><span class="line"><span class="cl">-clientserver      +jumplist          +postscript        +vartabs
</span></span><span class="line"><span class="cl">-clipboard         +keymap            +printer           +vertsplit
</span></span><span class="line"><span class="cl">+cmdline_compl     +lambda            +profile           +virtualedit
</span></span><span class="line"><span class="cl">+cmdline_hist      +langmap           -python            +visual
</span></span><span class="line"><span class="cl">+cmdline_info      +libcall           +python3           +visualextra
</span></span><span class="line"><span class="cl">+comments          +linebreak         +quickfix          +viminfo
</span></span><span class="line"><span class="cl">+conceal           +lispindent        +reltime           +vreplace
</span></span><span class="line"><span class="cl">+cryptv            +listcmds          +rightleft         +wildignore
</span></span><span class="line"><span class="cl">+cscope            +localmap          -ruby              +wildmenu
</span></span><span class="line"><span class="cl">+cursorbind        -lua               +scrollbind        +windows
</span></span><span class="line"><span class="cl">+cursorshape       +menu              +signs             +writebackup
</span></span><span class="line"><span class="cl">+dialog_con        +mksession         +smartindent       -X11
</span></span><span class="line"><span class="cl">+diff              +modify_fname      +sound             -xfontset
</span></span><span class="line"><span class="cl">+digraphs          +mouse             +spell             -xim
</span></span><span class="line"><span class="cl">-dnd               -mouseshape        +startuptime       -xpm
</span></span><span class="line"><span class="cl">-ebcdic            +mouse_dec         +statusline        -xsmp
</span></span><span class="line"><span class="cl">+emacs_tags        +mouse_gpm         -sun_workshop      -xterm_clipboard
</span></span><span class="line"><span class="cl">+eval              -mouse_jsbterm     +syntax            -xterm_save
</span></span><span class="line"><span class="cl">+ex_extra          +mouse_netterm     +tag_binary        
</span></span><span class="line"><span class="cl">+extra_search      +mouse_sgr         -tag_old_static    
</span></span><span class="line"><span class="cl">   system vimrc file: <span class="s2">&#34;</span><span class="nv">$VIM</span><span class="s2">/vimrc</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">     user vimrc file: <span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/.vimrc</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"> 2nd user vimrc file: <span class="s2">&#34;~/.vim/vimrc&#34;</span>
</span></span><span class="line"><span class="cl">      user exrc file: <span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/.exrc</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">       defaults file: <span class="s2">&#34;</span><span class="nv">$VIMRUNTIME</span><span class="s2">/defaults.vim</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">  fall-back <span class="k">for</span> <span class="nv">$VIM</span>: <span class="s2">&#34;/usr/share/vim&#34;</span>
</span></span><span class="line"><span class="cl">Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H   -Wdate-time  -g -O2 -fdebug-prefix-map<span class="o">=</span>/build/vim-iU6mZD/vim-8.1.2269<span class="o">=</span>. -fstack-protector-strong -Wformat -Werror<span class="o">=</span>format-security -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE<span class="o">=</span><span class="m">1</span>       
</span></span><span class="line"><span class="cl">Linking: gcc   -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -o vim        -lm -ltinfo -lnsl  -lselinux  -lcanberra -lacl -lattr -lgpm -ldl     -L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -lpython3.8 -lcrypt -lpthread -ldl -lutil -lm -lm   
</span></span></code></pre>
<h2>Implementation<a name='implementation'></h2>

<p>Having compiled languages like Go or C, the build date and version can be added
at the build process by setting the corresponding variables.</p>

<p>For the date one can use <code>date '+%Y-%m-%dT%H:%M:%S%z'</code> and the latest commit sha as version via <code>git describe --always</code>.</p>

<h3>Go<a name='go'></h3>

<p>The variables <code>BuildDate</code> and <code>BuildVersion</code> can be set
during a go build like the following: <code>go build -ldflags &quot;-X main.BuildDate=&lt;date&gt; -X main.BuildVersion=&lt;version&gt;&quot;</code></p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;flag&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">BuildDate</span>    <span class="kt">string</span>
</span></span><span class="line"><span class="cl">  <span class="nx">BuildVersion</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Version</span>      <span class="p">=</span> <span class="nx">flag</span><span class="p">.</span><span class="nf">Bool</span><span class="p">(</span><span class="s">&#34;version&#34;</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="s">&#34;Print build information&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">flag</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="o">*</span><span class="nx">Version</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;BuildVersion: &#34;</span><span class="p">,</span> <span class="nx">BuildVersion</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;BuildDate: &#34;</span><span class="p">,</span> <span class="nx">BuildDate</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<h3>C<a name='c'></h3>

<p>With the gcc version and date can be added as key-value pair using the <code>-D</code> prefix like the following:
<code>gcc -DBUILD_DATE=&quot;\&quot;DATE\&quot;&quot; -DBUILD_VERSION=&quot;\&quot;VERSION\&quot;&quot; main.c</code></p>

<p>Where <code>main.c</code> looks like this:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">ifndef BUILD_DATE</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">define BUILD_DATE &#34;BUILD_DATE is missing&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">endif</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cp">#</span><span class="cp">ifndef BUILD_VERSION</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">define BUILD_VERSION &#34;BUILD_VERSION is missing&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="cp">#</span><span class="cp">endif</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span> <span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span><span class="n">argv</span><span class="p">[</span><span class="p">]</span> <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span><span class="p">(</span> <span class="n">argc</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="o">&amp;</span><span class="o">&amp;</span> <span class="n">strcmp</span><span class="p">(</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="p">,</span> <span class="sa"></span><span class="s">&#34;</span><span class="s">--version</span><span class="s">&#34;</span> <span class="p">)</span> <span class="o">=</span><span class="o">=</span> <span class="mi">0</span> <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">printf</span><span class="p">(</span> <span class="sa"></span><span class="s">&#34;</span><span class="s">BuildDate: %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">BUILD_DATE</span> <span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">printf</span><span class="p">(</span> <span class="sa"></span><span class="s">&#34;</span><span class="s">BuildVersion: %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">BUILD_VERSION</span> <span class="p">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<h2>Further ideas<a name='ideas'></h2>

<p>Some inspiration which variables could be added to the build information:</p>

<ul>
<li>last commit message</li>
<li>last committer</li>
<li>version of the compiler/runtime</li>
<li>target platform</li>
</ul>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 12 Jan 2021 12:45:38 +0100</pubDate>
    </item>
    <item>
      <title>AoC day7</title>
      <link>https://evilcookie.de/aoc-day7.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>AoC day7</h1>

<p>Today&rsquo;s puzzles were about bags which contain a certain amount of other bags (and
so on) based on the rules from the input. The first one asks for the amount of
different bags in which our -shiny gold- one is contained. The second one asks
for the count of bags the own contains.</p>

<h2>Abstraction</h2>

<p>Let&rsquo;s say each bag is a node and each rule is an edge with the count as
edge-value. Then this problem can be converted into a <em>graph theory</em> one. Since
this puzzle is solvable it can be assumed that the graph has no circles.
Furthermore it can be assumed that this graph is a tree starting with the own
bag -shiny gold- as root. Bags which contain no further one are the leaves. All
other graphs not related to this tree (if any) are irrelevant and can be ignored.</p>

<p>This tree can be traversed for both puzzles recursively with an ordinary depth
search. Below is an implementation of a depth search finding a node in a given
tree.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Node</span> <span class="p">[</span><span class="p">]</span><span class="kt">string</span>
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Tree</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="nx">Node</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">depthSearch</span><span class="p">(</span><span class="nx">current</span><span class="p">,</span> <span class="nx">goal</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">tree</span> <span class="nx">Tree</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nx">current</span> <span class="o">==</span> <span class="nx">goal</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="nx">subNode</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">tree</span><span class="p">[</span><span class="nx">current</span><span class="p">]</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nf">depthSearch</span><span class="p">(</span><span class="nx">subNode</span><span class="p">,</span> <span class="nx">goal</span><span class="p">,</span> <span class="nx">tree</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>In this simplified depth search, a tree maps nodes name to a node. A node is a list of all related sub nodes identified by node names.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Node</span> <span class="p">[</span><span class="p">]</span><span class="kt">string</span>
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Tree</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="nx">Node</span>
</span></span></code></pre>
<p>The signature takes the current- such as the goal node name and the tree itself
returning if the goal has been reached.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">depthSearch</span><span class="p">(</span><span class="nx">current</span><span class="p">,</span> <span class="nx">goal</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">tree</span> <span class="nx">Tree</span><span class="p">)</span> <span class="kt">bool</span> 
</span></span></code></pre>
<p>The abort condition of this recursion is satisfied if the goal has been reached.
One can move this condition to the sub node loop. But imo it is code style to
put it at the very first showing any reader when this recursion ends such as
preventing errors leading to stack overflows.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">if</span> <span class="nx">current</span> <span class="o">==</span> <span class="nx">goal</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>To go in depth, the loop iterates over all sub nodes and calls itself for each
one. On reaching the goal the search immediately returns <code>true</code> and arises from
the depth. If the goal hasn&rsquo;t been reached a search terminates if a node hasn&rsquo;t any further sub nodes.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">for</span> <span class="nx">subNode</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">tree</span><span class="p">[</span><span class="nx">current</span><span class="p">]</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nf">depthSearch</span><span class="p">(</span><span class="nx">subNode</span><span class="p">,</span> <span class="nx">goal</span><span class="p">,</span> <span class="nx">tree</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="kc">false</span>
</span></span></code></pre>
<h2>Puzzle 1 - Find node</h2>

<p>It should be counted how many nodes contain our -shiny gold- bag. This can be
accomplished by searching it in each unique node and round the times it could be
found.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nx">found</span> <span class="o">:=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">tree</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nf">depthSearch</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="s">&#34;shiny gold&#34;</span><span class="p">,</span> <span class="nx">tree</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">found</span><span class="o">++</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>The code from the last section can be used directly for the search.</p>

<h2>Puzzle 2 - Count payload</h2>

<p>In this puzzle, each bag has various amounts of sub nodes. Those amounts are not
relevant for the search itself and called payload from here.</p>

<p>In contrast to the abstraction the below function is more a graph traversal than
a search. Since the payload of all nodes is needed to calculate the total count
of bags, the whole tree has to be traversed.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Node</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Tree</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="nx">Node</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">DepthSearch</span><span class="p">(</span><span class="nx">current</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">tree</span> <span class="nx">Tree</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">total</span> <span class="o">:=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="nx">subNode</span><span class="p">,</span> <span class="nx">count</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">tree</span><span class="p">[</span><span class="nx">current</span><span class="p">]</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">total</span> <span class="o">+=</span> <span class="nx">count</span> <span class="o">*</span> <span class="nf">DepthSearch</span><span class="p">(</span><span class="nx">subNode</span><span class="p">,</span> <span class="nx">tree</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">total</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Each node is now a mapping from sub node names to its payload. A tree is still a mapping from node name to node.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Node</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Tree</span> <span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="nx">Node</span>
</span></span></code></pre>
<p>No goal is necessary anymore since all nodes have to be visited and the search returns the total amount based on the given calculation from AoC.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">DepthSearch</span><span class="p">(</span><span class="nx">current</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">tree</span> <span class="nx">Tree</span><span class="p">)</span> <span class="kt">int</span>
</span></span></code></pre>
<p>Initially, the total amount of <em>sub bags</em> is set to one in order to return the
count for the current bag itself. This is also the reason why the final count is
off by one. For example: A tree only containing our -shiny bag- has a count of zero and not the count of contained bags.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nx">total</span> <span class="o">:=</span> <span class="mi">1</span>
</span></span></code></pre>
<p>Using the payload and the return value of the
depth search, the amount of all bags inside one sub bag can be calculated.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">for</span> <span class="nx">subNode</span><span class="p">,</span> <span class="nx">count</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">tree</span><span class="p">[</span><span class="nx">current</span><span class="p">]</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">total</span> <span class="o">+=</span> <span class="nx">count</span> <span class="o">*</span> <span class="nf">DepthSearch</span><span class="p">(</span><span class="nx">subNode</span><span class="p">,</span> <span class="nx">tree</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>Finally return the calculated/found amount of bags. Note that the definition of
<code>total</code> and this return will be the only effective lines in leaves (nodes
without any sub nodes).</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">return</span> <span class="nx">total</span>
</span></span></code></pre>
<p>PS: I need to find alternatives for &lsquo;the&rsquo; beginning of sentences&hellip;</p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Mon, 07 Dec 2020 18:35:56 +0100</pubDate>
    </item>
    <item>
      <title>AoC day1</title>
      <link>https://evilcookie.de/aoc-day1.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>AoC day 1</h1>

<p>The puzzles of day one were easy to solve in the first place, but have more
potential to optimize than I thought.</p>

<h2>Problem</h2>

<p><em>Find n addends which add up to 2020. Solution of the puzzle is the product of all addends</em> where <code>n=2</code> in puzzle one and <code>n=3</code> in puzzle two.</p>

<h2>Solution</h2>

<p>The idea was to find all unique subsets with n elements, where <code>n=2</code> in the
algorithm below.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="c1">// ex: input array of integers
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="nx">ex</span><span class="p">)</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="nx">j</span> <span class="o">:=</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">j</span> <span class="p">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="nx">ex</span><span class="p">)</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nx">ex</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="o">+</span><span class="nx">ex</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2020</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;Found %d + %d = 2020\n&#34;</span><span class="p">,</span> <span class="nx">ex</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="p">,</span> <span class="nx">ex</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;%d x %d = %d\n&#34;</span><span class="p">,</span> <span class="nx">ex</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="p">,</span> <span class="nx">ex</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="p">,</span> <span class="nx">ex</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">*</span> <span class="nx">ex</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre>
<p>The count of nested loops is equal to <code>n</code> which makes each subset accessible in
the innermost loop. To ensure that the subset is unique, each inner loop starts
with the index of the next outer loop plus one. By adding one all subsets are
being skipped which share the same number.</p>

<p>Uniqueness is important to conquer both: Performance and wrong solutions.
With unique subsets less than half the sums have to be calculated. Despite that,
the puzzle says that all addends have to be different.</p>

<h2>Visualization</h2>

<p>On <code>n=2</code>, a simple brute force approach where the indices of all nested loops
start at zero could be visualized with the following table. It shows the sum of
<em>all</em> subsets with two elements made up from the input .</p>

<table>
<thead>
<tr>
<th></th>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
</tr>
</thead>

<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>

<tr>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
</tr>

<tr>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>

<tr>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
<td>8</td>
</tr>
</tbody>
</table>
<p>The first observation one can make is the symmetry of the table. This is
caused by the <em>commutation property of addition</em> which basically states that
<code>x+y = y+x</code>. Good for us, we can get rid of almost one half and reduce the iteration count.</p>

<p>The next observation, is the diagonal. It is only made up of sums where the addends are equal. Better for us, we can get rid of them
either.</p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 01 Dec 2020 13:03:45 +0100</pubDate>
    </item>
    <item>
      <title>AoC</title>
      <link>https://evilcookie.de/aoc.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>AoC</h1>

<p>The annual advent-of-code challenge is starting again at first of December. Ruby
was my last years choice of language, which I also used to do the <a href="https://github.com/RaphaelPour/advent-of-code">2015
event</a> for preparation. This year I go with Go
since the majority of my daily projects are Go ones. My goal is to give each puzzle a serious try and write a post about interesting solutions.</p>

<h2>Experience</h2>

<p>All puzzles are based on some kind of data transformation. Each puzzle provides a customized
input which needs to be transformed in order to get the solution.
Ruby is a good first AoC language since parsing and transforming data are easy
to implement out-of-the-box with native regex-support and a lot of map-reduce
functions.</p>

<h2>Expectation</h2>

<p>Using Go over Ruby for the same kind of data transformation is more complex and
time-consuming. Go has no native map-reduce and therefore all transformations
have to be done manually with (nested) loops which also get unreadable with
higher complexity.
On the other side I want to gain more experience with Go, since I&rsquo;m fairly new
to the language while I wrote my first line of code around December 2019.</p>

<h2>References</h2>

<ul>
<li><a href="https://adventofcode.com/">Advent of code</a></li>
<li><a href="https://github.com/RaphaelPour/aoc2020">My solutions</a></li>
</ul>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Tue, 24 Nov 2020 13:09:39 +0100</pubDate>
    </item>
    <item>
      <title>Hello internet</title>
      <link>https://evilcookie.de/hello-internet.html</link>
      <description></description>
      <content:encoded><![CDATA[<h1>Hello internet</h1>

<p>This blog is managed via <a href="https://github.com/RaphaelPour/blogctl">blogctl</a> and served via caddy container half-automatic.
I build blogctl and the edit-and-publish workflow having the following things in
mind:</p>

<ul>
<li>focus: CLI-only, no distractions</li>
<li>simplicity: only the features currently needed</li>
<li>minimalism: focus on content and not style</li>
</ul>

<p>That&rsquo;s my premise for writing blog posts at least mid-term. I am easily
distractible and need a clean environment.</p>
]]></content:encoded>
      <author>Raphael Pour</author>
      <pubDate>Sun, 04 Oct 2020 14:07:48 +0200</pubDate>
    </item>
  </channel>
</rss>