<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Marco Kamner</title>
    <description>The latest articles on DEV Community by Marco Kamner (@professorlogout).</description>
    <link>https://dev.to/professorlogout</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F134112%2F54bd4f83-2ea5-409f-9814-e0483ad7dc9f.jpeg</url>
      <title>DEV Community: Marco Kamner</title>
      <link>https://dev.to/professorlogout</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/professorlogout"/>
    <language>en</language>
    <item>
      <title>Static Site Generator Fulltext Search</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Sun, 26 Oct 2025 16:29:12 +0000</pubDate>
      <link>https://dev.to/professorlogout/static-site-generator-fulltext-search-4fdf</link>
      <guid>https://dev.to/professorlogout/static-site-generator-fulltext-search-4fdf</guid>
      <description>&lt;p&gt;I recently rebuilt my blog from scratch, see the previous post in this series.&lt;/p&gt;

&lt;p&gt;One thing I wanted to add was site-wide search without any external dependencies. Since I have previous experience with a tool called &lt;a href="https://pagefind.app" rel="noopener noreferrer"&gt;pagefind&lt;/a&gt;, which is perfect for this use case, I implemented it with that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marco.ninja/blog/posts/2025/10/26/static-site-generator-fulltext-search/" rel="noopener noreferrer"&gt;Read more&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hugo</category>
      <category>pagefind</category>
      <category>search</category>
    </item>
    <item>
      <title>Remaking My Blog From Scratch</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Sun, 26 Oct 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/professorlogout/remaking-my-blog-from-scratch-fkk</link>
      <guid>https://dev.to/professorlogout/remaking-my-blog-from-scratch-fkk</guid>
      <description>&lt;p&gt;I’ve been blogging in one form or another for 5 years now.&lt;/p&gt;

&lt;p&gt;All blogs and other online publishing adventures had one thing in common: I barely knew what I was doing, using components I never learned properly.&lt;/p&gt;

&lt;p&gt;I wanted to change that! And with the benefit of hindsight I will now take you on this adventure with me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marco.ninja/blog/posts/2025/10/26/remaking-my-blog-from-scratch/" rel="noopener noreferrer"&gt;Read more&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hugo</category>
      <category>python</category>
      <category>blogging</category>
    </item>
    <item>
      <title>Colorize pattern on CLI</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Wed, 07 May 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/professorlogout/colorize-pattern-on-cli-59ee</link>
      <guid>https://dev.to/professorlogout/colorize-pattern-on-cli-59ee</guid>
      <description>&lt;p&gt;Colorize a pattern in the given input using a neat regex and colorization hack in grep (&lt;code&gt;$&lt;/code&gt; matching all lines but not being able to be highlighted).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;color &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;# Color highlight the pattern in the incoming stream, writing to stdout&lt;/span&gt;
  &lt;span class="c"&gt;# This effectively matches our PATTERN any "$" (lines end character)&lt;/span&gt;
  &lt;span class="c"&gt;# But only our PATTERN can be highlighted, line end characters aren't actually there to be highlighted&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;PATTERN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage: color &amp;lt;pattern&amp;gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Description: Greps input with --color=always -E 'PATTERN|&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;' "&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Example: echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;hello world&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; | color &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;world&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;1

  &lt;span class="k"&gt;fi
  &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;--color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATTERN&lt;/span&gt;&lt;span class="se"&gt;\|\$&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>cli</category>
      <category>scripting</category>
      <category>bash</category>
    </item>
    <item>
      <title>pip install from git repository</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Mon, 14 Apr 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/professorlogout/pip-install-from-git-repository-592d</link>
      <guid>https://dev.to/professorlogout/pip-install-from-git-repository-592d</guid>
      <description>&lt;p&gt;Install a pip package from a git repo, using a specified git reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$REPOSITORY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://gitlab.com/mkamner/example.git"&lt;/span&gt;
&lt;span class="nv"&gt;$GIT_REF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-branch-or-tag-or-sha"&lt;/span&gt;

pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"git+&lt;/span&gt;&lt;span class="nv"&gt;$REPOSITORY&lt;/span&gt;&lt;span class="s2"&gt;/@&lt;/span&gt;&lt;span class="nv"&gt;$GIT_REF&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the package resides in a sub-directory this can be specified like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$REPOSITORY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://gitlab.com/mkamner/example.git"&lt;/span&gt;
&lt;span class="nv"&gt;$GIT_REF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-branch-or-tag-or-sha"&lt;/span&gt;
&lt;span class="nv"&gt;$DIRECTORY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-folder"&lt;/span&gt;

pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"git+&lt;/span&gt;&lt;span class="nv"&gt;$REPOSITORY&lt;/span&gt;&lt;span class="s2"&gt;/@&lt;/span&gt;&lt;span class="nv"&gt;$GIT_REF&lt;/span&gt;&lt;span class="s2"&gt;#subdirectory=&lt;/span&gt;&lt;span class="nv"&gt;$DIRECTORY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>python</category>
      <category>devops</category>
    </item>
    <item>
      <title>Troubleshooting Intermittent DNS Resolution Issues</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Fri, 28 Feb 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/professorlogout/troubleshooting-intermittent-dns-resolution-issues-5106</link>
      <guid>https://dev.to/professorlogout/troubleshooting-intermittent-dns-resolution-issues-5106</guid>
      <description>&lt;p&gt;DNS is something so fundamental to most of our systems functioning that it’s often overlooked in initial troubleshooting, it’s also incredibly hard to troubleshoot if it’s only intermittently failing.&lt;/p&gt;

&lt;p&gt;The below script helps me in doing this kind of troubleshooting by effectively bombarding a DNS server with requests&lt;br&gt;
and reporting whenever the response changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;dns_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nv"&gt;dns_server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
&lt;span class="nv"&gt;detail_log_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$detail_log_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nv"&gt;detail_log_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/dev/stdout"&lt;/span&gt;
&lt;span class="k"&gt;fi


if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dns_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dns_server&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$detail_log_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;dns_name&amp;gt; &amp;lt;dns_server&amp;gt; [detail_log_file=/dev/stdout]"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;previous_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c"&gt;# Run the dig command&lt;/span&gt;
    &lt;span class="nv"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dig +short &lt;span class="nv"&gt;$dns_name&lt;/span&gt; &lt;span class="s2"&gt;"@&lt;/span&gt;&lt;span class="nv"&gt;$dns_server&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# Check the exit status of the dig command&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$output&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$previous_output&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nv"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="s2"&gt;"%Y-%m-%d %H:%M:%S"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[&lt;/span&gt;&lt;span class="nv"&gt;$timestamp&lt;/span&gt;&lt;span class="s2"&gt;] dig response changed"&lt;/span&gt;

        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"------"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$detail_log_file&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# [&lt;/span&gt;&lt;span class="nv"&gt;$timestamp&lt;/span&gt;&lt;span class="s2"&gt;] response changed"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$detail_log_file&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# previous response"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$detail_log_file&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$previous_output&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$detail_log_file&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# new response"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$detail_log_file&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$output&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$detail_log_file&lt;/span&gt;

        &lt;span class="nv"&gt;previous_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$output&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://blog.marco.ninja/notes/technology/dns/troubleshooting-intermittent-dns-resolution-issues/" rel="noopener noreferrer"&gt;Read more&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>troubleshooting</category>
      <category>dns</category>
    </item>
    <item>
      <title>GitLab Copy &amp; Paste: Added Backticks</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/professorlogout/gitlab-copy-paste-added-backticks-5fn0</link>
      <guid>https://dev.to/professorlogout/gitlab-copy-paste-added-backticks-5fn0</guid>
      <description>&lt;h1&gt;
  
  
  Problem
&lt;/h1&gt;

&lt;p&gt;When copying (using either select and copy or the copy icon) a line of code like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;atlantis apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then pasting it into GitLabs comment field the contents get enclosed in backticks like &lt;code&gt;`atlantis apply`&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;GitLab tries to be helpful and adds that to make pasting with formatting (the default on all modern systems) easier.&lt;/p&gt;

&lt;p&gt;in this case we need it without formatting, so doing a paste without formatting works.&lt;/p&gt;

&lt;p&gt;On MacOS: Shift + Command + V&lt;/p&gt;

&lt;p&gt;On Windows/Linux: Ctrl + Shift + v&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.marco.ninja/notes/technology/gitlab/gitlab-pasting-ticks/" rel="noopener noreferrer"&gt;Read more&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gitlab</category>
    </item>
    <item>
      <title>Running Multiple Server Processes From One Script</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Sun, 23 Feb 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/professorlogout/running-multiple-server-processes-from-one-script-cj7</link>
      <guid>https://dev.to/professorlogout/running-multiple-server-processes-from-one-script-cj7</guid>
      <description>&lt;p&gt;Doing local development on a bunch of interconnected services I often want to start multiple long running server processes.&lt;/p&gt;

&lt;p&gt;This is the basic script I use for that.&lt;/p&gt;

&lt;p&gt;It has the added niceness of prefixing output with an identifier so you know which process it came from.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nv"&gt;pids&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;

cleanup&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"CONTROL: Cleaning up, killing all processes"&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;pid &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pids&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pid&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;done
  &lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;trap &lt;/span&gt;cleanup SIGINT

start_process&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;shift&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s2"&gt;"s/^/&lt;/span&gt;&lt;span class="nv"&gt;$prefix&lt;/span&gt;&lt;span class="s2"&gt;: /"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 2&amp;gt; &lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s2"&gt;"s/^/&lt;/span&gt;&lt;span class="nv"&gt;$prefix&lt;/span&gt;&lt;span class="s2"&gt; (err): /"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2&lt;span class="o"&gt;)&lt;/span&gt;
  pids+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="nv"&gt;$!&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Place your processes here&lt;/span&gt;
start_process &lt;span class="s2"&gt;"A"&lt;/span&gt; python3 &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 9000
start_process &lt;span class="s2"&gt;"B"&lt;/span&gt; python3 &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 9001

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"CONTROL: All processes started, streaming stdout and stderr"&lt;/span&gt;

&lt;span class="nb"&gt;wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://blog.marco.ninja/notes/technology/bash/running-multiple-server-processes-script/" rel="noopener noreferrer"&gt;Read more&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>bash</category>
      <category>scripting</category>
    </item>
    <item>
      <title>Simple Redirect View for Django</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Thu, 02 Jan 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/professorlogout/simple-redirect-view-for-django-4n1l</link>
      <guid>https://dev.to/professorlogout/simple-redirect-view-for-django-4n1l</guid>
      <description>&lt;p&gt;I often find myself replacing an existing MVP based on static html with a Django app, or just needing to preserve some old URL scheme.&lt;/p&gt;

&lt;p&gt;This is the code I use to do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.shortcuts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;redirect_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;redirectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;permanent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redirectable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which can then be used like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;old-url/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redirect_view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;redirectable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new_view&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some-thing/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redirect_view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;redirectable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some_thing_new&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;permanent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>Cleanup After Script Exit</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Tue, 03 Sep 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/professorlogout/cleanup-after-script-exit-1efk</link>
      <guid>https://dev.to/professorlogout/cleanup-after-script-exit-1efk</guid>
      <description>&lt;p&gt;Many of my scripts work with temporary files, usually relative to the scripts directory, while at the same time using &lt;code&gt;set -e&lt;/code&gt; to exit as soon as something fails.&lt;/p&gt;

&lt;p&gt;In this scenario the script leaves behind these temporary files by default, which is not desirable.&lt;/p&gt;

&lt;p&gt;We can however do a proper cleanup using the &lt;code&gt;trap&lt;/code&gt; concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nv"&gt;MY_TMP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/my-dir

&lt;span class="k"&gt;function &lt;/span&gt;cleanup &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Removing &lt;/span&gt;&lt;span class="nv"&gt;$MY_TMP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nv"&gt;$MY_TMP_DIR&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;trap &lt;/span&gt;cleanup EXIT
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nv"&gt;$MY_TMP_DIR&lt;/span&gt;
&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://blog.marco.ninja/notes/technology/linux/cleanup-after-script-exit/" rel="noopener noreferrer"&gt;Read more&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>devops</category>
      <category>scripting</category>
    </item>
    <item>
      <title>Vault CLI in Containers</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Thu, 25 Jul 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/professorlogout/vault-cli-in-containers-3gco</link>
      <guid>https://dev.to/professorlogout/vault-cli-in-containers-3gco</guid>
      <description>&lt;p&gt;In many CI/CD workflows interfacing with Hashicorp Vault is required.&lt;/p&gt;

&lt;p&gt;However, their CLI (or better called unified binary&lt;sup id="fnref1"&gt;1&lt;/sup&gt;) is stupidly big with more than 400MB&lt;br&gt;
and they seem to have no interest in making it any smaller&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;This is often a undesired size increase, especially when optimizing for pull and run time in CI/CD.&lt;/p&gt;

&lt;p&gt;This note outlines a solution that brings us down from 400MB+ on disk for &lt;code&gt;vault&lt;/code&gt; to about 300KB using &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;jq&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Optimizing things
&lt;/h2&gt;

&lt;p&gt;The simple actions of getting keys in Vault can easily be expressed using plain &lt;code&gt;curl&lt;/code&gt;, in combination with a bit of &lt;code&gt;jq&lt;/code&gt; or &lt;code&gt;bash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I will demonstrate with this simple example: Getting the value of a key in a secret for use somewhere else&lt;/p&gt;

&lt;p&gt;With the vault CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault kv get &lt;span class="nt"&gt;-address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"vault-host"&lt;/span&gt;  &lt;span class="nt"&gt;-mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;X &lt;span class="nt"&gt;-field&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;username Some/secret/path
&lt;span class="c"&gt;# myusername&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could simply build the curl command ourself, but vault has the &lt;code&gt;-output-curl-string&lt;/code&gt; flag that gives us a curl command to work with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault kv get &lt;span class="nt"&gt;-address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"vault-host"&lt;/span&gt;  &lt;span class="nt"&gt;-mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;X &lt;span class="nt"&gt;-field&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;username &lt;span class="nt"&gt;-output-curl-string&lt;/span&gt; Some/secret/path
&lt;span class="c"&gt;# curl -H "X-Vault-Token: $(vault print token)" -H "X-Vault-Request: true" https://vault-host/v1/X/data/Some/secret/path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command might already be enough for your use-case, but it does not replicate the &lt;code&gt;-field=username&lt;/code&gt; parameter yet, instead it outputs the whole object.&lt;br&gt;
Using &lt;code&gt;jq&lt;/code&gt; we can achieve the exact same output as the original &lt;code&gt;vault&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Vault-Token: &lt;/span&gt;&lt;span class="nv"&gt;$VAULT_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Vault-Request: true"&lt;/span&gt; https://vault-host/v1/X/data/Some/secret/path &lt;span class="nt"&gt;--silent&lt;/span&gt; | jq .data.data.username &lt;span class="nt"&gt;-r&lt;/span&gt;
&lt;span class="c"&gt;# myusername&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://github.com/hashicorp/vault/issues/10180" rel="noopener noreferrer"&gt;https://github.com/hashicorp/vault/issues/10180&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://github.com/hashicorp/vault/issues/22893" rel="noopener noreferrer"&gt;https://github.com/hashicorp/vault/issues/22893&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>hashicorp</category>
      <category>vault</category>
      <category>devops</category>
      <category>curl</category>
    </item>
    <item>
      <title>Caddy: Manual Maintenance Mode</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Sat, 13 Jul 2024 15:57:10 +0000</pubDate>
      <link>https://dev.to/professorlogout/caddy-manual-maintenance-mode-273d</link>
      <guid>https://dev.to/professorlogout/caddy-manual-maintenance-mode-273d</guid>
      <description>&lt;p&gt;Coming from NGINX and others the concept of a maintenance mode that can be manually enabled is something I have used many times before.&lt;/p&gt;

&lt;p&gt;With Caddy it is equally as easy, just using a less obvious syntax.&lt;/p&gt;

&lt;p&gt;It always follows this general pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check if a &lt;code&gt;maintenance.on&lt;/code&gt; file exists at a specified location&lt;/li&gt;
&lt;li&gt;If it does, deliver the maintenance page&lt;/li&gt;
&lt;li&gt;Otherwise, do the normal thing you do&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Notice&lt;/strong&gt;:&lt;br&gt;
Doing maintenance pages the way I describe in this post means your webserver is checking a file on disk for every request.&lt;/p&gt;

&lt;p&gt;In small deployments this is likely not adding any overhead you need to be concerned with, but keep it in mind.&lt;/p&gt;
&lt;h2&gt;
  
  
  nginx
&lt;/h2&gt;

&lt;p&gt;To refresh your memory, this patterns looks like this in nginx.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;$maintenance&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;if&lt;/span&gt; &lt;span class="s"&gt;(-f&lt;/span&gt; &lt;span class="n"&gt;/app/maintenance.on&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kn"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;$maintenance&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kn"&gt;if&lt;/span&gt; &lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$maintenance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kn"&gt;rewrite&lt;/span&gt; &lt;span class="s"&gt;^(.*)&lt;/span&gt;$ &lt;span class="n"&gt;/app/static/maintenance.html&lt;/span&gt; &lt;span class="s"&gt;last&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Caddyfile
&lt;/h2&gt;

&lt;p&gt;With Caddy it works exactly the same, just using a different vocabulary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;example.marco.ninja {
    @maintenanceModeActive file /app/maintenance.on
    handle @maintenanceModeActive {
        try_files /app/static/maintenance.html
        file_server {
            status 503
        }
    }

    reverse_proxy 127.0.0.1:8080
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>PicoCSS Sticky Footer</title>
      <dc:creator>Marco Kamner</dc:creator>
      <pubDate>Mon, 10 Jun 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/professorlogout/picocss-sticky-footer-1mhc</link>
      <guid>https://dev.to/professorlogout/picocss-sticky-footer-1mhc</guid>
      <description>&lt;p&gt;A sticky footer using &lt;a href="https://picocss.com" rel="noopener noreferrer"&gt;PicoCSS&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;html,
body {
  height: 100vh;
}

body &amp;gt; footer {
  position: sticky;
  top: 100vh;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>css</category>
    </item>
  </channel>
</rss>
