<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Stefan VanBuren · TILs</title>
    <link>https://stefan.vanburen.xyz/til/</link>
    <description>TILs on stefan.vanburen.xyz</description>
    <language>en-us</language>
    
    
    <managingEditor>stefan@vanburen.xyz (Stefan VanBuren)</managingEditor>
    <webMaster>stefan@vanburen.xyz (Stefan VanBuren)</webMaster>
    <copyright>©️ 2026 Stefan VanBuren</copyright>
    
    
      <atom:link href="https://stefan.vanburen.xyz/til/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Neovim :Inspect</title>
      <link>https://stefan.vanburen.xyz/til/neovim-inspect/</link>
      <pubDate>Sat, 10 Jan 2026 16:26:47 -0500</pubDate>
      <guid>https://stefan.vanburen.xyz/til/neovim-inspect/</guid>
      <description>&lt;p&gt;Yesterday, I was working on &lt;a href=&#34;https://github.com/bufbuild/buf/pull/4270&#34;&gt;improving &lt;code&gt;buf&lt;/code&gt;&amp;rsquo;s lsp protobuf semantic tokens&lt;/a&gt;,
and needed to test out how my changes were working in a real LSP client.&lt;/p&gt;
&lt;p&gt;I knew neovim had a couple of helper functions for inspecting the current position;
first I tried:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-vim&#34; data-lang=&#34;vim&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lua&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;vim&lt;/span&gt;.&lt;span class=&#34;nx&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;vim&lt;/span&gt;.&lt;span class=&#34;nx&#34;&gt;inspect_pos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I figured there must be a function more specifically for semantic tokens:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-vim&#34; data-lang=&#34;vim&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lua&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;vim&lt;/span&gt;.&lt;span class=&#34;nx&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;vim&lt;/span&gt;.&lt;span class=&#34;nx&#34;&gt;lsp&lt;/span&gt;.&lt;span class=&#34;nx&#34;&gt;semantic_tokens&lt;/span&gt;.&lt;span class=&#34;nx&#34;&gt;get_at_pos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But finally I landed on:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-vim&#34; data-lang=&#34;vim&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Inspect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(&lt;a href=&#34;https://neovim.io/doc/user/lua.html#%3AInspect%21&#34;&gt;neovim docs&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;which prints both treesitter and semantic tokens,
but in a much cleaner way than the two lua functions.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve &lt;a href=&#34;https://github.com/stefanvanburen/dotfiles/commit/7dadb128015d37030f7b3b55b1e849b2873e499b&#34;&gt;keymapped the underlying &lt;code&gt;vim.show_pos()&lt;/code&gt; function to &lt;code&gt;&amp;lt;leader&amp;gt;i&lt;/code&gt; in neovim&lt;/a&gt; for easier access.&lt;/p&gt;
</description>
      <source:markdown><p>Yesterday, I was working on <a href="https://github.com/bufbuild/buf/pull/4270">improving <code>buf</code>&rsquo;s lsp protobuf semantic tokens</a>,
and needed to test out how my changes were working in a real LSP client.</p>
<p>I knew neovim had a couple of helper functions for inspecting the current position;
first I tried:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="p">:</span><span class="nx">lua</span> <span class="nx">vim</span>.<span class="nx">print</span><span class="p">(</span><span class="nx">vim</span>.<span class="nx">inspect_pos</span><span class="p">())</span>
</span></span></code></pre></div><p>I figured there must be a function more specifically for semantic tokens:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="p">:</span><span class="nx">lua</span> <span class="nx">vim</span>.<span class="nx">print</span><span class="p">(</span><span class="nx">vim</span>.<span class="nx">lsp</span>.<span class="nx">semantic_tokens</span>.<span class="nx">get_at_pos</span><span class="p">())</span>
</span></span></code></pre></div><p>But finally I landed on:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="p">:</span><span class="nx">Inspect</span>
</span></span></code></pre></div><p>(<a href="https://neovim.io/doc/user/lua.html#%3AInspect%21">neovim docs</a>)</p>
<p>which prints both treesitter and semantic tokens,
but in a much cleaner way than the two lua functions.</p>
<p>I&rsquo;ve <a href="https://github.com/stefanvanburen/dotfiles/commit/7dadb128015d37030f7b3b55b1e849b2873e499b">keymapped the underlying <code>vim.show_pos()</code> function to <code>&lt;leader&gt;i</code> in neovim</a> for easier access.</p>
</source:markdown>
    </item>
    
    <item>
      <title>Neovim :InspectTree Tree-sitter</title>
      <link>https://stefan.vanburen.xyz/til/nvim-inspect-tree-sitter/</link>
      <pubDate>Wed, 10 Sep 2025 19:50:36 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/nvim-inspect-tree-sitter/</guid>
      <description>&lt;p&gt;I had assumed that to interact with Tree-sitter in Neovim,
you still needed to use the utilities from &lt;a href=&#34;https://github.com/nvim-treesitter/nvim-treesitter&#34;&gt;nvim-treesitter&lt;/a&gt;.
Apparently that&amp;rsquo;s not the case &amp;mdash;
Neovim has had a builtin &lt;a href=&#34;https://neovim.io/doc/user/treesitter.html#%3AInspectTree&#34;&gt;&lt;code&gt;:InspectTree&lt;/code&gt;&lt;/a&gt; command that brings up the AST from Tree-sitter in a split window,
which is &lt;a href=&#34;https://neovim.io/doc/user/options.html#&#39;scrollbind&#39;&#34;&gt;&lt;code&gt;scrollbound&lt;/code&gt;&lt;/a&gt; to the original window and highlights the selected node in both windows.&lt;/p&gt;
&lt;p&gt;It also has a &lt;a href=&#34;https://gpanders.com/blog/whats-new-in-neovim-0.10/#tree-sitter-query-editor&#34;&gt;query editor&lt;/a&gt;,
which I haven&amp;rsquo;t yet had the need for,
but it&amp;rsquo;s good to know it exists.&lt;/p&gt;
</description>
      <source:markdown><p>I had assumed that to interact with Tree-sitter in Neovim,
you still needed to use the utilities from <a href="https://github.com/nvim-treesitter/nvim-treesitter">nvim-treesitter</a>.
Apparently that&rsquo;s not the case &mdash;
Neovim has had a builtin <a href="https://neovim.io/doc/user/treesitter.html#%3AInspectTree"><code>:InspectTree</code></a> command that brings up the AST from Tree-sitter in a split window,
which is <a href="https://neovim.io/doc/user/options.html#'scrollbind'"><code>scrollbound</code></a> to the original window and highlights the selected node in both windows.</p>
<p>It also has a <a href="https://gpanders.com/blog/whats-new-in-neovim-0.10/#tree-sitter-query-editor">query editor</a>,
which I haven&rsquo;t yet had the need for,
but it&rsquo;s good to know it exists.</p>
</source:markdown>
    </item>
    
    <item>
      <title>WikiGnome</title>
      <link>https://stefan.vanburen.xyz/til/wiki-gnome/</link>
      <pubDate>Tue, 02 Sep 2025 09:10:30 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/wiki-gnome/</guid>
      <description>&lt;p&gt;TIL about &lt;a href=&#34;https://en.m.wikipedia.org/wiki/Wikipedia:WikiGnome&#34;&gt;WikiGnomes&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A WikiGnome is a wiki user who makes useful incremental edits without clamoring for attention.
WikiGnomes work behind the scenes of a wiki, tying up little loose ends and making things run more smoothly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some of the most valuable work can be the tiny changes that leave things in a better place than they were found.&lt;/p&gt;
&lt;p&gt;Also, sounds a little like &lt;a href=&#34;../../blog/prutsen&#34;&gt;prutsen&lt;/a&gt;.&lt;/p&gt;
</description>
      <source:markdown><p>TIL about <a href="https://en.m.wikipedia.org/wiki/Wikipedia:WikiGnome">WikiGnomes</a>:</p>
<blockquote>
<p>A WikiGnome is a wiki user who makes useful incremental edits without clamoring for attention.
WikiGnomes work behind the scenes of a wiki, tying up little loose ends and making things run more smoothly.</p>
</blockquote>
<p>Some of the most valuable work can be the tiny changes that leave things in a better place than they were found.</p>
<p>Also, sounds a little like <a href="../../blog/prutsen">prutsen</a>.</p>
</source:markdown>
    </item>
    
    <item>
      <title>Wrapping arrays in jq</title>
      <link>https://stefan.vanburen.xyz/til/jq-wrap-array/</link>
      <pubDate>Wed, 20 Aug 2025 08:55:08 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/jq-wrap-array/</guid>
      <description>&lt;p&gt;Riffing on &lt;a href=&#34;https://macwright.com/2025/08/19/using-super&#34;&gt;Tom MacWright&amp;rsquo;s &amp;ldquo;Using super&amp;rdquo; post&lt;/a&gt; from yesterday,
I saw the post and immediately thought of using &lt;a href=&#34;https://jqlang.org&#34;&gt;&lt;code&gt;jq&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I thought I might get what he was looking for with my initial attempt, something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gp&#34;&gt;$&lt;/span&gt; pbpaste &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq &lt;span class=&#34;s1&#34;&gt;&amp;#39;.[].name&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;go&#34;&gt;&amp;#34;ALGOLIA_API_KEY&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;go&#34;&gt;&amp;#34;AMAZON_AWS_ACCESS_KEY_ID&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; but that left out the wrapper array.
I figured I might need some other &lt;code&gt;jq&lt;/code&gt; function or pipe,
but instead I found that you can just wrap the entire expression in square brackets to wrap the result:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gp&#34;&gt;$&lt;/span&gt; pbpaste &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq &lt;span class=&#34;s1&#34;&gt;&amp;#39;[.[].name]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;go&#34;&gt;&amp;#34;ALGOLIA_API_KEY&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;go&#34;&gt;&amp;#34;AMAZON_AWS_ACCESS_KEY_ID&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Regardless, &lt;code&gt;jq&lt;/code&gt; feels worth the investment,
especially given &lt;a href=&#34;https://github.com/fiatjaf/awesome-jq&#34;&gt;the community (and alternative implementations)&lt;/a&gt; built up around it.&lt;/p&gt;
</description>
      <source:markdown><p>Riffing on <a href="https://macwright.com/2025/08/19/using-super">Tom MacWright&rsquo;s &ldquo;Using super&rdquo; post</a> from yesterday,
I saw the post and immediately thought of using <a href="https://jqlang.org"><code>jq</code></a>.</p>
<p>I thought I might get what he was looking for with my initial attempt, something like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> pbpaste <span class="p">|</span> jq <span class="s1">&#39;.[].name&#39;</span>
</span></span><span class="line"><span class="cl"><span class="go">&#34;ALGOLIA_API_KEY&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">&#34;AMAZON_AWS_ACCESS_KEY_ID&#34;
</span></span></span></code></pre></div><p>&hellip; but that left out the wrapper array.
I figured I might need some other <code>jq</code> function or pipe,
but instead I found that you can just wrap the entire expression in square brackets to wrap the result:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> pbpaste <span class="p">|</span> jq <span class="s1">&#39;[.[].name]&#39;</span>
</span></span><span class="line"><span class="cl"><span class="go">&#34;ALGOLIA_API_KEY&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">&#34;AMAZON_AWS_ACCESS_KEY_ID&#34;
</span></span></span></code></pre></div><p>Regardless, <code>jq</code> feels worth the investment,
especially given <a href="https://github.com/fiatjaf/awesome-jq">the community (and alternative implementations)</a> built up around it.</p>
</source:markdown>
    </item>
    
    <item>
      <title>Neovim LSP Defaults</title>
      <link>https://stefan.vanburen.xyz/til/neovim-lsp-defaults/</link>
      <pubDate>Tue, 01 Jul 2025 16:33:55 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/neovim-lsp-defaults/</guid>
      <description>&lt;p&gt;neovim released v0.11.0 a little while back,
and in the interest of using the defaults,
I &lt;a href=&#34;https://github.com/stefanvanburen/dotfiles/commit/8f8ad882a1092c8c032b13e118efc960317759f4#diff-568ff9545a264b9c3d0daec0395b05bf4217c6448328e6f2e70b1ad55adcbd4eL533-R534&#34;&gt;removed some of my LSP-related keymaps&lt;/a&gt; that are now &lt;a href=&#34;https://gpanders.com/blog/whats-new-in-neovim-0-11/#defaults&#34;&gt;automatically mapped&lt;/a&gt;.
These are listed at &lt;a href=&#34;https://neovim.io/doc/user/lsp.html#_defaults&#34;&gt;&lt;code&gt;:help lsp-defaults&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
</description>
      <source:markdown><p>neovim released v0.11.0 a little while back,
and in the interest of using the defaults,
I <a href="https://github.com/stefanvanburen/dotfiles/commit/8f8ad882a1092c8c032b13e118efc960317759f4#diff-568ff9545a264b9c3d0daec0395b05bf4217c6448328e6f2e70b1ad55adcbd4eL533-R534">removed some of my LSP-related keymaps</a> that are now <a href="https://gpanders.com/blog/whats-new-in-neovim-0-11/#defaults">automatically mapped</a>.
These are listed at <a href="https://neovim.io/doc/user/lsp.html#_defaults"><code>:help lsp-defaults</code></a>.</p>
</source:markdown>
    </item>
    
    <item>
      <title>Postgres citext type</title>
      <link>https://stefan.vanburen.xyz/til/postgres-citext/</link>
      <pubDate>Wed, 21 Aug 2024 07:49:04 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/postgres-citext/</guid>
      <description>&lt;p&gt;TIL about the Postgres &lt;code&gt;citext&lt;/code&gt; type (that is, &lt;a href=&#34;https://www.postgresql.org/docs/current/citext.html&#34;&gt;case-insensitive text type&lt;/a&gt;),
from reading &lt;a href=&#34;https://github.com/surprisetalk/ding/blob/main/db.sql#L18-L19&#34;&gt;this schema&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Based on this tip from the Postgres docs,
this might not be the right type for general text:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Consider using nondeterministic collations (see &lt;a href=&#34;https://www.postgresql.org/docs/current/collation.html#COLLATION-NONDETERMINISTIC&#34;&gt;Section 24.2.2.4&lt;/a&gt;) instead of this module.
They can be used for case-insensitive comparisons,
accent-insensitive comparisons,
and other combinations,
and they handle more Unicode special cases correctly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;hellip; but if you&amp;rsquo;re storing something like a username or email address that&amp;rsquo;s already limited to an ascii-ish character set,
and want to keep things unique on a case-insensitive basis,
it might be what you&amp;rsquo;re looking for.&lt;/p&gt;
</description>
      <source:markdown><p>TIL about the Postgres <code>citext</code> type (that is, <a href="https://www.postgresql.org/docs/current/citext.html">case-insensitive text type</a>),
from reading <a href="https://github.com/surprisetalk/ding/blob/main/db.sql#L18-L19">this schema</a>.</p>
<p>Based on this tip from the Postgres docs,
this might not be the right type for general text:</p>
<blockquote>
<p>Consider using nondeterministic collations (see <a href="https://www.postgresql.org/docs/current/collation.html#COLLATION-NONDETERMINISTIC">Section 24.2.2.4</a>) instead of this module.
They can be used for case-insensitive comparisons,
accent-insensitive comparisons,
and other combinations,
and they handle more Unicode special cases correctly.</p>
</blockquote>
<p>&hellip; but if you&rsquo;re storing something like a username or email address that&rsquo;s already limited to an ascii-ish character set,
and want to keep things unique on a case-insensitive basis,
it might be what you&rsquo;re looking for.</p>
</source:markdown>
    </item>
    
    <item>
      <title>Go Pass by Value or Pointer</title>
      <link>https://stefan.vanburen.xyz/til/go-passing/</link>
      <pubDate>Sun, 18 Aug 2024 19:09:03 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/go-passing/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve long struggled with the choice of how to pass around Go values,
specifically structs.
I was happy to find &lt;a href=&#34;https://blog.percywegmann.com/2023/09/20/go-pass-by-value-or-pointer.html&#34;&gt;this article&lt;/a&gt; on the topic,
specifically the conclusion,
reproduced here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Types that are not structs or arrays should be passed by value.&lt;/li&gt;
&lt;li&gt;Struct types that don’t export their members and are clearly built as immutable value types, like time.Time, should be passed by value. Note that these types are relatively rare, and are even rarer to be defined by you.&lt;/li&gt;
&lt;li&gt;Arrays and all other struct types should be passed by pointer, whether small, large, stateful, or whatever.&lt;/li&gt;
&lt;li&gt;If you’re passing data that could be mutated by a concurrent process and its important to you for that data not to be mutated, explicitly make a copy of it before passing it along. Be aware that you can’t just rely on passing the data by value since that does not create a deep copy.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;ll be referencing this moving forward,
and taking the guesswork out of my passing conventions.&lt;/p&gt;
</description>
      <source:markdown><p>I&rsquo;ve long struggled with the choice of how to pass around Go values,
specifically structs.
I was happy to find <a href="https://blog.percywegmann.com/2023/09/20/go-pass-by-value-or-pointer.html">this article</a> on the topic,
specifically the conclusion,
reproduced here:</p>
<blockquote>
<ol>
<li>Types that are not structs or arrays should be passed by value.</li>
<li>Struct types that don’t export their members and are clearly built as immutable value types, like time.Time, should be passed by value. Note that these types are relatively rare, and are even rarer to be defined by you.</li>
<li>Arrays and all other struct types should be passed by pointer, whether small, large, stateful, or whatever.</li>
<li>If you’re passing data that could be mutated by a concurrent process and its important to you for that data not to be mutated, explicitly make a copy of it before passing it along. Be aware that you can’t just rely on passing the data by value since that does not create a deep copy.</li>
</ol>
</blockquote>
<p>I&rsquo;ll be referencing this moving forward,
and taking the guesswork out of my passing conventions.</p>
</source:markdown>
    </item>
    
    <item>
      <title>HTML datetime duration</title>
      <link>https://stefan.vanburen.xyz/til/html-date-duration/</link>
      <pubDate>Sat, 13 Jul 2024 10:18:24 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/html-date-duration/</guid>
      <description>&lt;p&gt;Last week I learned that an HTML &lt;code&gt;datetime&lt;/code&gt; attribute can &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time#valid_datetime_values&#34;&gt;represent a duration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;PT4H18M3S&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  4 hours, 18 minutes and 3 seconds
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The syntax is an &lt;a href=&#34;https://en.wikipedia.org/wiki/ISO_8601#Durations&#34;&gt;ISO 8601 Duration&lt;/a&gt;.&lt;/p&gt;
</description>
      <source:markdown><p>Last week I learned that an HTML <code>datetime</code> attribute can <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time#valid_datetime_values">represent a duration</a>.</p>
<p>For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">time</span> <span class="na">datetime</span><span class="o">=</span><span class="s">&#34;PT4H18M3S&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  4 hours, 18 minutes and 3 seconds
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">time</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The syntax is an <a href="https://en.wikipedia.org/wiki/ISO_8601#Durations">ISO 8601 Duration</a>.</p>
</source:markdown>
    </item>
    
    <item>
      <title>GBrowse to another branch with Fugitive.vim</title>
      <link>https://stefan.vanburen.xyz/til/fugitive-objects/</link>
      <pubDate>Thu, 11 Jul 2024 08:28:24 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/fugitive-objects/</guid>
      <description>&lt;p&gt;Last week, I watched a coworker bring up a file on a different branch using fugitive.vim&amp;rsquo;s &lt;a href=&#34;https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L254&#34;&gt;:GBrowse&lt;/a&gt; and I was floored:
almost daily I find myself using it to open the URL to a file to share (or a few lines).&lt;/p&gt;
&lt;p&gt;However, much of the time I&amp;rsquo;m working on a different branch than the one I want to share,
and navigating to the same file on a different branch in the GitHub UI takes too many steps.
First, you realize you&amp;rsquo;re on the wrong branch,
then you change branches,
then you have to navigate back to the file again.&lt;/p&gt;
&lt;p&gt;I had always been vaguely aware of &lt;a href=&#34;https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L611&#34;&gt;&lt;code&gt;:h fugitive-object&lt;/code&gt;&lt;/a&gt;,
but had never put them to use.&lt;/p&gt;
&lt;p&gt;The object you&amp;rsquo;re looking for is &lt;code&gt;&amp;lt;branch&amp;gt;:%&lt;/code&gt;, meaning:
bring up this file (&lt;code&gt;%&lt;/code&gt;) on branch &lt;code&gt;&amp;lt;branch&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-vim&#34; data-lang=&#34;vim&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GBrowse&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;:%
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And of course, this just works with all of the &lt;a href=&#34;https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L264-L277&#34;&gt;&lt;code&gt;:GBrowse&lt;/code&gt; variants&lt;/a&gt;.&lt;/p&gt;
</description>
      <source:markdown><p>Last week, I watched a coworker bring up a file on a different branch using fugitive.vim&rsquo;s <a href="https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L254">:GBrowse</a> and I was floored:
almost daily I find myself using it to open the URL to a file to share (or a few lines).</p>
<p>However, much of the time I&rsquo;m working on a different branch than the one I want to share,
and navigating to the same file on a different branch in the GitHub UI takes too many steps.
First, you realize you&rsquo;re on the wrong branch,
then you change branches,
then you have to navigate back to the file again.</p>
<p>I had always been vaguely aware of <a href="https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L611"><code>:h fugitive-object</code></a>,
but had never put them to use.</p>
<p>The object you&rsquo;re looking for is <code>&lt;branch&gt;:%</code>, meaning:
bring up this file (<code>%</code>) on branch <code>&lt;branch&gt;</code>.</p>
<p>For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="p">:</span><span class="nx">GBrowse</span> <span class="nx">main</span>:%
</span></span></code></pre></div><p>And of course, this just works with all of the <a href="https://github.com/tpope/vim-fugitive/blob/8c8cdf4405cb8bdb70dd9812a33bb52363a87dbc/doc/fugitive.txt#L264-L277"><code>:GBrowse</code> variants</a>.</p>
</source:markdown>
    </item>
    
    <item>
      <title>Neovim nfnl Directory Configuration</title>
      <link>https://stefan.vanburen.xyz/til/nvim-nfnl-directory-configuration/</link>
      <pubDate>Fri, 31 May 2024 08:16:19 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/nvim-nfnl-directory-configuration/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve long wanted to figure out how to get &lt;a href=&#34;https://github.com/olical/nfnl?tab=readme-ov-file#directory-local-neovim-configuration-in-fennel&#34;&gt;&lt;code&gt;nfnl&#39;s&lt;/code&gt; directory-local configuration&lt;/a&gt; working,
but it took me until yesterday to figure it out &amp;mdash;
mostly by &lt;a href=&#34;https://github.com/Olical/nfnl/discussions/41&#34;&gt;opening a discussion&lt;/a&gt; and then realizing my mistakes. 🤡&lt;/p&gt;
&lt;p&gt;First, &lt;code&gt;exrc&lt;/code&gt; needs to be &lt;a href=&#34;https://github.com/stefanvanburen/dotfiles/commit/beed66f9a0a872f2a0db07b0e2de36ad262e4649&#34;&gt;enabled&lt;/a&gt;.
This will ultimately load the contents of the generated &lt;code&gt;.nvim.lua&lt;/code&gt; file,
as described in &lt;a href=&#34;https://neovim.io/doc/user/options.html#&#39;exrc&#39;&#34;&gt;&lt;code&gt;:help &#39;exrc&#39;&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next, create an &lt;code&gt;.nfnl.fnl&lt;/code&gt; file in the directory.
I&amp;rsquo;ve been creating mine as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;; .nfnl.fnl&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:source-file-patterns&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:.nvim.fnl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; which means that &lt;code&gt;nfnl&lt;/code&gt; only needs to compile the &lt;code&gt;.nvim.fnl&lt;/code&gt; file into &lt;code&gt;.nvim.lua&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From there, I create a &lt;code&gt;.nvim.fnl&lt;/code&gt; file with my configuration.
Often this is to set up a particular project-local formatter or linter with conform or nvim-lint,
so it may look something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;; .nvim.fnl&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;conform&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;require &lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:conform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;set &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;conform.formatters_by_ft.json&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:prettier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this I&amp;rsquo;ve been able to &lt;a href=&#34;https://github.com/stefanvanburen/dotfiles/commit/b7ab7019510c4554e5eb432996bb8378d9e9bd44&#34;&gt;remove a few $WORK specific formatters&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lastly, I&amp;rsquo;ve &lt;a href=&#34;https://github.com/stefanvanburen/dotfiles/commit/1d740e2a0337678eb6084e4c97cd0a096ea46a71&#34;&gt;globally gitignored&lt;/a&gt; these files so they aren&amp;rsquo;t accidentally committed.
It&amp;rsquo;s possible to commit the &lt;code&gt;.nvim.lua&lt;/code&gt; files to share with other neovim users that have &lt;code&gt;exrc&lt;/code&gt; enabled,
but I doubt I&amp;rsquo;ll use that very often &amp;mdash;
I&amp;rsquo;m still undecided on if I&amp;rsquo;ll commit these for my personal projects.&lt;/p&gt;
&lt;p&gt;📁&lt;/p&gt;
</description>
      <source:markdown><p>I&rsquo;ve long wanted to figure out how to get <a href="https://github.com/olical/nfnl?tab=readme-ov-file#directory-local-neovim-configuration-in-fennel"><code>nfnl's</code> directory-local configuration</a> working,
but it took me until yesterday to figure it out &mdash;
mostly by <a href="https://github.com/Olical/nfnl/discussions/41">opening a discussion</a> and then realizing my mistakes. 🤡</p>
<p>First, <code>exrc</code> needs to be <a href="https://github.com/stefanvanburen/dotfiles/commit/beed66f9a0a872f2a0db07b0e2de36ad262e4649">enabled</a>.
This will ultimately load the contents of the generated <code>.nvim.lua</code> file,
as described in <a href="https://neovim.io/doc/user/options.html#'exrc'"><code>:help 'exrc'</code></a></p>
<p>Next, create an <code>.nfnl.fnl</code> file in the directory.
I&rsquo;ve been creating mine as:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fennel" data-lang="fennel"><span class="line"><span class="cl"><span class="c1">;; .nfnl.fnl</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">{</span><span class="ss">:source-file-patterns</span><span class="w"> </span><span class="p">[</span><span class="ss">:.nvim.fnl</span><span class="p">]}</span><span class="w">
</span></span></span></code></pre></div><p>&hellip; which means that <code>nfnl</code> only needs to compile the <code>.nvim.fnl</code> file into <code>.nvim.lua</code>.</p>
<p>From there, I create a <code>.nvim.fnl</code> file with my configuration.
Often this is to set up a particular project-local formatter or linter with conform or nvim-lint,
so it may look something like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fennel" data-lang="fennel"><span class="line"><span class="cl"><span class="c1">;; .nvim.fnl</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">conform</span><span class="w"> </span><span class="p">(</span><span class="nb">require </span><span class="ss">:conform</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="k">set </span><span class="nv">conform.formatters_by_ft.json</span><span class="w"> </span><span class="p">[</span><span class="ss">:prettier</span><span class="p">]))</span><span class="w">
</span></span></span></code></pre></div><p>With this I&rsquo;ve been able to <a href="https://github.com/stefanvanburen/dotfiles/commit/b7ab7019510c4554e5eb432996bb8378d9e9bd44">remove a few $WORK specific formatters</a>.</p>
<p>Lastly, I&rsquo;ve <a href="https://github.com/stefanvanburen/dotfiles/commit/1d740e2a0337678eb6084e4c97cd0a096ea46a71">globally gitignored</a> these files so they aren&rsquo;t accidentally committed.
It&rsquo;s possible to commit the <code>.nvim.lua</code> files to share with other neovim users that have <code>exrc</code> enabled,
but I doubt I&rsquo;ll use that very often &mdash;
I&rsquo;m still undecided on if I&rsquo;ll commit these for my personal projects.</p>
<p>📁</p>
</source:markdown>
    </item>
    
    <item>
      <title>Git Stash File(s)</title>
      <link>https://stefan.vanburen.xyz/til/git-stash-file/</link>
      <pubDate>Fri, 24 May 2024 07:39:46 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/git-stash-file/</guid>
      <description>&lt;p&gt;This isn&amp;rsquo;t something I&amp;rsquo;m just learning today,
but I&amp;rsquo;ve looked this up enough to warrant writing it down.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m often working on some code,
and come across something unrelated that I want to change.
So I do &amp;mdash; but it really doesn&amp;rsquo;t belong in this commit or PR/patch/etc.!&lt;/p&gt;
&lt;p&gt;(I&amp;rsquo;ve yet to put in the reps to understand &lt;a href=&#34;https://git-scm.com/docs/git-worktree&#34;&gt;worktrees&lt;/a&gt; or &lt;a href=&#34;https://martinvonz.github.io/jj&#34;&gt;jujutsu&lt;/a&gt;,
which I&amp;rsquo;m assuming are the &amp;ldquo;real&amp;rdquo; answers here.)&lt;/p&gt;
&lt;p&gt;For now, you can provide &lt;code&gt;git stash push&lt;/code&gt; a filename (or multiple!) to come back to those changes later:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gp&#34;&gt;$&lt;/span&gt; git stash push &amp;lt;filename&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;s&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m sure there&amp;rsquo;s also a way to do this incrementally with &lt;code&gt;-p&lt;/code&gt; or &lt;a href=&#34;https://github.com/tpope/vim-fugitive&#34;&gt;Fugitive&amp;rsquo;s&lt;/a&gt; interface.&lt;/p&gt;
&lt;p&gt;📦&lt;/p&gt;
</description>
      <source:markdown><p>This isn&rsquo;t something I&rsquo;m just learning today,
but I&rsquo;ve looked this up enough to warrant writing it down.</p>
<p>I&rsquo;m often working on some code,
and come across something unrelated that I want to change.
So I do &mdash; but it really doesn&rsquo;t belong in this commit or PR/patch/etc.!</p>
<p>(I&rsquo;ve yet to put in the reps to understand <a href="https://git-scm.com/docs/git-worktree">worktrees</a> or <a href="https://martinvonz.github.io/jj">jujutsu</a>,
which I&rsquo;m assuming are the &ldquo;real&rdquo; answers here.)</p>
<p>For now, you can provide <code>git stash push</code> a filename (or multiple!) to come back to those changes later:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git stash push &lt;filename<span class="o">(</span>s<span class="o">)</span>&gt;
</span></span></code></pre></div><p>I&rsquo;m sure there&rsquo;s also a way to do this incrementally with <code>-p</code> or <a href="https://github.com/tpope/vim-fugitive">Fugitive&rsquo;s</a> interface.</p>
<p>📦</p>
</source:markdown>
    </item>
    
    <item>
      <title>Service Wrappers</title>
      <link>https://stefan.vanburen.xyz/til/service-wrappers/</link>
      <pubDate>Tue, 01 Nov 2022 18:54:05 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/service-wrappers/</guid>
      <description>&lt;p&gt;TIL of &lt;a href=&#34;https://naildrivin5.com/blog/2022/10/31/wrap-third-party-apis-in-service-wrappers-to-simplify-your-code.html&#34;&gt;Service Wrappers&lt;/a&gt;
a technique I&amp;rsquo;ve used in the past but have never had a name for.
It&amp;rsquo;s essentially an approach to wrapping external APIs.
From the article:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Methods should be named in the language of the service, not the language of the app.&lt;/li&gt;
&lt;li&gt;Arguments should use the domain of the service, not the domain of the app.&lt;/li&gt;
&lt;li&gt;Arguments should be whatever type is directly needed by the service, so passing in complex stuff like Active Record should be avoided.&lt;/li&gt;
&lt;li&gt;The return value should not be a complex object from the third party, but ideally only what data a caller will need (often nothing at all). If it must be a complex object, its name or properties should be in the domain of the service.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;The article is written from a Rails perspective,
but is broadly useful &amp;mdash;
always nice to have a name for something useful!&lt;/p&gt;
</description>
      <source:markdown><p>TIL of <a href="https://naildrivin5.com/blog/2022/10/31/wrap-third-party-apis-in-service-wrappers-to-simplify-your-code.html">Service Wrappers</a>
a technique I&rsquo;ve used in the past but have never had a name for.
It&rsquo;s essentially an approach to wrapping external APIs.
From the article:</p>
<blockquote>
<ul>
<li>Methods should be named in the language of the service, not the language of the app.</li>
<li>Arguments should use the domain of the service, not the domain of the app.</li>
<li>Arguments should be whatever type is directly needed by the service, so passing in complex stuff like Active Record should be avoided.</li>
<li>The return value should not be a complex object from the third party, but ideally only what data a caller will need (often nothing at all). If it must be a complex object, its name or properties should be in the domain of the service.</li>
</ul>
</blockquote>
<p>The article is written from a Rails perspective,
but is broadly useful &mdash;
always nice to have a name for something useful!</p>
</source:markdown>
    </item>
    
    <item>
      <title>Go&#39;s fmt package Explicit Argument Indexes</title>
      <link>https://stefan.vanburen.xyz/til/fmt-explicit-argument-indexes/</link>
      <pubDate>Fri, 24 Jun 2022 15:59:17 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/fmt-explicit-argument-indexes/</guid>
      <description>&lt;p&gt;Not sure how I hadn&amp;rsquo;t seen this before:
in Go, you can specify the index of the format argument you want to use for each formatting verb.&lt;/p&gt;
&lt;p&gt;Simply enough, from the &lt;a href=&#34;https://pkg.go.dev/fmt#hdr-Explicit_argument_indexes&#34;&gt;package docs&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Sprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%[2]d %[1]d\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// =&amp;gt; &amp;#34;22 11&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the past, I&amp;rsquo;ve actually done something along the lines of:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Sprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%s %s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// =&amp;gt; &amp;#34;test test&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instead, you can do:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Sprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%[1]s %[1]s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// =&amp;gt; &amp;#34;test test&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This came up today at $WORK while providing a table name to a constructed SQL query -
the table name needed to be supplied multiple times in an upsert, so we could simply do:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;query&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Sprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;INSERT INTO %[1]s (...) VALUES ($1, $2)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;ON CONFLICT (...) DO UPDATE SET ... = %[1]s.(...) WHERE %[1]s.(...) = $2;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tableName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instead of needing to supply &lt;code&gt;tableName&lt;/code&gt; three times,
it could be supplied once using &lt;code&gt;%[1]s&lt;/code&gt;.&lt;/p&gt;
</description>
      <source:markdown><p>Not sure how I hadn&rsquo;t seen this before:
in Go, you can specify the index of the format argument you want to use for each formatting verb.</p>
<p>Simply enough, from the <a href="https://pkg.go.dev/fmt#hdr-Explicit_argument_indexes">package docs</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;%[2]d %[1]d\n&#34;</span><span class="p">,</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"> </span><span class="mi">22</span><span class="p">)</span><span class="w"> </span><span class="c1">// =&gt; &#34;22 11&#34;</span><span class="w">
</span></span></span></code></pre></div><p>In the past, I&rsquo;ve actually done something along the lines of:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&#34;test&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;%s %s&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">)</span><span class="w"> </span><span class="c1">// =&gt; &#34;test test&#34;</span><span class="w">
</span></span></span></code></pre></div><p>Instead, you can do:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&#34;test&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;%[1]s %[1]s&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">)</span><span class="w"> </span><span class="c1">// =&gt; &#34;test test&#34;</span><span class="w">
</span></span></span></code></pre></div><p>This came up today at $WORK while providing a table name to a constructed SQL query -
the table name needed to be supplied multiple times in an upsert, so we could simply do:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">query</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">`
</span></span></span><span class="line"><span class="cl"><span class="s">INSERT INTO %[1]s (...) VALUES ($1, $2)
</span></span></span><span class="line"><span class="cl"><span class="s">ON CONFLICT (...) DO UPDATE SET ... = %[1]s.(...) WHERE %[1]s.(...) = $2;
</span></span></span><span class="line"><span class="cl"><span class="s">`</span><span class="p">,</span><span class="w"> </span><span class="nx">tableName</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p>Instead of needing to supply <code>tableName</code> three times,
it could be supplied once using <code>%[1]s</code>.</p>
</source:markdown>
    </item>
    
    <item>
      <title>SQLite Connection Configuration</title>
      <link>https://stefan.vanburen.xyz/til/sqlite-connection-configuration/</link>
      <pubDate>Sat, 02 Apr 2022 10:54:44 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/sqlite-connection-configuration/</guid>
      <description>&lt;p&gt;These notes are basically cribbed from Ben Johnson&amp;rsquo;s excellent &amp;ldquo;Building Production Applications Using Go &amp;amp; SQLite&amp;rdquo; GopherCon talk,
specifically the &lt;a href=&#34;https://youtu.be/XcAYkriuQ1o?t=430&#34;&gt;&amp;ldquo;Configuring SQLite&amp;rdquo; section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Generally speaking, you&amp;rsquo;ll want to set three &lt;code&gt;PRAGMA&lt;/code&gt;s on each SQLite connection:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;PRAGMA&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;journal_mode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;WAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;PRAGMA&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;busy_timeout&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;PRAGMA&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;foreign_keys&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In turn,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://sqlite.org/pragma.html#pragma_journal_mode&#34;&gt;&lt;code&gt;PRAGMA journal_mode = WAL;&lt;/code&gt;&lt;/a&gt; sets the database into &lt;a href=&#34;https://sqlite.org/wal.html#activating_and_configuring_wal_mode&#34;&gt;WAL journaling mode&lt;/a&gt;.
Unlike the others,
this doesn&amp;rsquo;t necessarily need to be set on each connection;
once a database is in WAL mode &lt;a href=&#34;https://sqlite.org/wal.html#persistence_of_wal_mode&#34;&gt;it&amp;rsquo;ll stay in that mode across database connections&lt;/a&gt;.
WAL journaling mode is recommended for most SQLite server applications,
because it makes writers not block readers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://sqlite.org/pragma.html#pragma_busy_timeout&#34;&gt;&lt;code&gt;PRAGMA busy_timeout = 5000;&lt;/code&gt;&lt;/a&gt; sets the &lt;a href=&#34;https://sqlite.org/c3ref/busy_timeout.html&#34;&gt;busy_timeout&lt;/a&gt; to 5000 milliseconds (5 seconds).
Without this setting,
if a write transaction is running,
and another write transaction starts,
the second write transaction will fail immediately.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://sqlite.org/pragma.html#pragma_foreign_keys&#34;&gt;&lt;code&gt;PRAGMA foreign_keys = ON;&lt;/code&gt;&lt;/a&gt; turns on SQLite&amp;rsquo;s &lt;a href=&#34;https://sqlite.org/foreignkeys.html&#34;&gt;foreign key support&lt;/a&gt;.
Foreign Keys aren&amp;rsquo;t enabled by default in SQLite for historical reasons,
but foreign keys are great for maintaining data integrity.
So &amp;ndash; use them!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;ins datetime=&#34;2024-06-30&#34;&gt;
  Update(2024-06-30): A more complete discussion of these settings and more can be found over at
  &lt;a href=&#34;https://kerkour.com/sqlite-for-servers&#34;&gt;kerkour.com/sqlite-for-servers&lt;/a&gt;
&lt;/ins&gt;
</description>
      <source:markdown><p>These notes are basically cribbed from Ben Johnson&rsquo;s excellent &ldquo;Building Production Applications Using Go &amp; SQLite&rdquo; GopherCon talk,
specifically the <a href="https://youtu.be/XcAYkriuQ1o?t=430">&ldquo;Configuring SQLite&rdquo; section</a>.</p>
<p>Generally speaking, you&rsquo;ll want to set three <code>PRAGMA</code>s on each SQLite connection:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="n">PRAGMA</span><span class="w"> </span><span class="n">journal_mode</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">WAL</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="n">PRAGMA</span><span class="w"> </span><span class="n">busy_timeout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">5000</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="n">PRAGMA</span><span class="w"> </span><span class="n">foreign_keys</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">ON</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>In turn,</p>
<ul>
<li>
<p><a href="https://sqlite.org/pragma.html#pragma_journal_mode"><code>PRAGMA journal_mode = WAL;</code></a> sets the database into <a href="https://sqlite.org/wal.html#activating_and_configuring_wal_mode">WAL journaling mode</a>.
Unlike the others,
this doesn&rsquo;t necessarily need to be set on each connection;
once a database is in WAL mode <a href="https://sqlite.org/wal.html#persistence_of_wal_mode">it&rsquo;ll stay in that mode across database connections</a>.
WAL journaling mode is recommended for most SQLite server applications,
because it makes writers not block readers.</p>
</li>
<li>
<p><a href="https://sqlite.org/pragma.html#pragma_busy_timeout"><code>PRAGMA busy_timeout = 5000;</code></a> sets the <a href="https://sqlite.org/c3ref/busy_timeout.html">busy_timeout</a> to 5000 milliseconds (5 seconds).
Without this setting,
if a write transaction is running,
and another write transaction starts,
the second write transaction will fail immediately.</p>
</li>
<li>
<p><a href="https://sqlite.org/pragma.html#pragma_foreign_keys"><code>PRAGMA foreign_keys = ON;</code></a> turns on SQLite&rsquo;s <a href="https://sqlite.org/foreignkeys.html">foreign key support</a>.
Foreign Keys aren&rsquo;t enabled by default in SQLite for historical reasons,
but foreign keys are great for maintaining data integrity.
So &ndash; use them!</p>
</li>
</ul>
<hr>
<ins datetime="2024-06-30">
  Update(2024-06-30): A more complete discussion of these settings and more can be found over at
  <a href="https://kerkour.com/sqlite-for-servers">kerkour.com/sqlite-for-servers</a>
</ins>
</source:markdown>
    </item>
    
    <item>
      <title>Shell in Markdown</title>
      <link>https://stefan.vanburen.xyz/til/markdown-shell/</link>
      <pubDate>Fri, 28 Jan 2022 16:23:20 -0500</pubDate>
      <guid>https://stefan.vanburen.xyz/til/markdown-shell/</guid>
      <description>&lt;p&gt;For a long time,
I&amp;rsquo;ve used &lt;code&gt;commandline&lt;/code&gt; as the name for the syntax of code fences in markdown whenever I&amp;rsquo;ve wanted to denote a shell command or session.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve now realized that I&amp;rsquo;ve been using the wrong name,
and also that there are two separate scenarios to keep in mind:&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The first scenario is one-off commands, which should use the syntax &lt;a href=&#34;https://github.com/github/linguist/blob/73e2d735c3c26577fc89c1cb3f8342e5a8ff1d82/lib/linguist/languages.yml#L5602&#34;&gt;&lt;code&gt;sh&lt;/code&gt;, or &lt;code&gt;shell&lt;/code&gt;&lt;/a&gt;.
This would be showing something you&amp;rsquo;d enter directly at the command line.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;brew install git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I leave out the &lt;a href=&#34;https://en.wikipedia.org/wiki/Command-line_interface#Command_prompt&#34;&gt;command prompt&lt;/a&gt;,
because it&amp;rsquo;s implied by the context that the line is to be entered in a command line.
Also, it helps with copy-paste.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The other scenario is showing a shell &lt;em&gt;session&lt;/em&gt;,
which typically shows the command prompt, an entered command, and &lt;em&gt;the response to the command&lt;/em&gt;.
In this instance I&amp;rsquo;d use the &lt;a href=&#34;https://github.com/github/linguist/blob/cddf7476af4c95d1572956ffc5c0cb84f7e431c5/lib/linguist/languages.yml#L5921&#34;&gt;&lt;code&gt;console&lt;/code&gt;, or &lt;code&gt;sh-session&lt;/code&gt;&lt;/a&gt; syntax.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gp&#34;&gt;$&lt;/span&gt; git st
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;go&#34;&gt;?? content/til/markdown-shell.md
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;🐚&lt;/p&gt;
</description>
      <source:markdown><p>For a long time,
I&rsquo;ve used <code>commandline</code> as the name for the syntax of code fences in markdown whenever I&rsquo;ve wanted to denote a shell command or session.</p>
<p>I&rsquo;ve now realized that I&rsquo;ve been using the wrong name,
and also that there are two separate scenarios to keep in mind:</p>
<hr>
<p>The first scenario is one-off commands, which should use the syntax <a href="https://github.com/github/linguist/blob/73e2d735c3c26577fc89c1cb3f8342e5a8ff1d82/lib/linguist/languages.yml#L5602"><code>sh</code>, or <code>shell</code></a>.
This would be showing something you&rsquo;d enter directly at the command line.</p>
<p>For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">brew install git
</span></span></code></pre></div><p>I leave out the <a href="https://en.wikipedia.org/wiki/Command-line_interface#Command_prompt">command prompt</a>,
because it&rsquo;s implied by the context that the line is to be entered in a command line.
Also, it helps with copy-paste.</p>
<hr>
<p>The other scenario is showing a shell <em>session</em>,
which typically shows the command prompt, an entered command, and <em>the response to the command</em>.
In this instance I&rsquo;d use the <a href="https://github.com/github/linguist/blob/cddf7476af4c95d1572956ffc5c0cb84f7e431c5/lib/linguist/languages.yml#L5921"><code>console</code>, or <code>sh-session</code></a> syntax.</p>
<p>For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git st
</span></span><span class="line"><span class="cl"><span class="go">?? content/til/markdown-shell.md
</span></span></span></code></pre></div><p>🐚</p>
</source:markdown>
    </item>
    
    <item>
      <title>PostgreSQL and jsonb type casts</title>
      <link>https://stefan.vanburen.xyz/til/postgres-jsonb-casting/</link>
      <pubDate>Wed, 19 Jan 2022 18:30:21 -0500</pubDate>
      <guid>https://stefan.vanburen.xyz/til/postgres-jsonb-casting/</guid>
      <description>&lt;p&gt;Found a bug in one of our systems at work that deals with &lt;a href=&#34;https://www.postgresql.org/docs/current/datatype-json.html&#34;&gt;jsonb data&lt;/a&gt; stored in Postgres today.
The quick summary is that one of our systems was looking for the maximum numerical value of a jsonb integer in a table.&lt;/p&gt;
&lt;p&gt;A very simplified example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-postgresql&#34; data-lang=&#34;postgresql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;balances&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;unnest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ARRAY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;{&amp;#34;balance&amp;#34;: 7}&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;jsonb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;balance&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;{&amp;#34;balance&amp;#34;: 17}&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;jsonb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;balance&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;balances&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This returns &lt;code&gt;7&lt;/code&gt;, because while the &amp;ldquo;balance&amp;rdquo; field is a numeric JSON value, the &lt;a href=&#34;https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSON-PROCESSING&#34;&gt;&lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; operator&lt;/a&gt; turns the value into text! &amp;mdash; which makes the comparison a lexicographical one.&lt;/p&gt;
&lt;p&gt;Instead, you need to make sure to &lt;a href=&#34;https://www.postgresql.org/docs/current/sql-expressions.html#SQL-SYNTAX-TYPE-CASTS&#34;&gt;cast the values&lt;/a&gt; before comparing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-postgresql&#34; data-lang=&#34;postgresql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;balances&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;unnest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ARRAY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;{&amp;#34;balance&amp;#34;: 7}&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;jsonb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;balance&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;integer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;{&amp;#34;balance&amp;#34;: 17}&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;jsonb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;balance&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;integer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;balances&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which returns the expected &lt;code&gt;17&lt;/code&gt;.&lt;/p&gt;
</description>
      <source:markdown><p>Found a bug in one of our systems at work that deals with <a href="https://www.postgresql.org/docs/current/datatype-json.html">jsonb data</a> stored in Postgres today.
The quick summary is that one of our systems was looking for the maximum numerical value of a jsonb integer in a table.</p>
<p>A very simplified example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-postgresql" data-lang="postgresql"><span class="line"><span class="cl"><span class="k">SELECT</span>
</span></span><span class="line"><span class="cl">  <span class="n">max</span><span class="p">(</span><span class="n">balances</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">FROM</span>
</span></span><span class="line"><span class="cl">  <span class="n">unnest</span><span class="p">(</span><span class="k">ARRAY</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;{&#34;balance&#34;: 7}&#39;</span><span class="o">::</span><span class="nb">jsonb</span><span class="o">-&gt;&gt;</span><span class="s1">&#39;balance&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;{&#34;balance&#34;: 17}&#39;</span><span class="o">::</span><span class="nb">jsonb</span><span class="o">-&gt;&gt;</span><span class="s1">&#39;balance&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="p">])</span> <span class="k">as</span> <span class="n">balances</span>
</span></span></code></pre></div><p>This returns <code>7</code>, because while the &ldquo;balance&rdquo; field is a numeric JSON value, the <a href="https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSON-PROCESSING"><code>-&gt;&gt;</code> operator</a> turns the value into text! &mdash; which makes the comparison a lexicographical one.</p>
<p>Instead, you need to make sure to <a href="https://www.postgresql.org/docs/current/sql-expressions.html#SQL-SYNTAX-TYPE-CASTS">cast the values</a> before comparing:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-postgresql" data-lang="postgresql"><span class="line"><span class="cl"><span class="k">SELECT</span>
</span></span><span class="line"><span class="cl">  <span class="n">max</span><span class="p">(</span><span class="n">balances</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">FROM</span>
</span></span><span class="line"><span class="cl">  <span class="n">unnest</span><span class="p">(</span><span class="k">ARRAY</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s1">&#39;{&#34;balance&#34;: 7}&#39;</span><span class="o">::</span><span class="nb">jsonb</span><span class="o">-&gt;&gt;</span><span class="s1">&#39;balance&#39;</span><span class="p">)</span><span class="o">::</span><span class="nb">integer</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s1">&#39;{&#34;balance&#34;: 17}&#39;</span><span class="o">::</span><span class="nb">jsonb</span><span class="o">-&gt;&gt;</span><span class="s1">&#39;balance&#39;</span><span class="p">)</span><span class="o">::</span><span class="nb">integer</span>
</span></span><span class="line"><span class="cl">  <span class="p">])</span> <span class="k">as</span> <span class="n">balances</span>
</span></span></code></pre></div><p>Which returns the expected <code>17</code>.</p>
</source:markdown>
    </item>
    
    <item>
      <title>PostgreSQL IN versus ANY</title>
      <link>https://stefan.vanburen.xyz/til/psql-in-versus-any/</link>
      <pubDate>Tue, 11 Jan 2022 08:40:46 -0500</pubDate>
      <guid>https://stefan.vanburen.xyz/til/psql-in-versus-any/</guid>
      <description>&lt;p&gt;I still feel rather new to PostgreSQL,
and a few times now in Go I&amp;rsquo;ve tried to do something along the lines of:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pgdb&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;DB&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pgdb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;getEntityByID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ids&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;query&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;SELECT * FROM entities WHERE entities.id IN ($1)&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rows&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;QueryContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;query&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;StringArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ids&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;/// ...&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But the query would always fail or retrieve no rows.
I&amp;rsquo;ve always fixed it by switching the &lt;code&gt;IN $1&lt;/code&gt; for a &lt;code&gt;= ANY($1)&lt;/code&gt;,
but never quite understood why.&lt;/p&gt;
&lt;p&gt;Researching this a bit more today,
I realized that the &lt;a href=&#34;https://www.postgresql.org/docs/current/functions-comparisons.html#FUNCTIONS-COMPARISONS-IN-SCALAR&#34;&gt;&lt;code&gt;IN&lt;/code&gt;&lt;/a&gt; function takes a list of literals,
whereas &lt;a href=&#34;https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.30.16&#34;&gt;&lt;code&gt;ANY&lt;/code&gt;&lt;/a&gt; is an array function that takes a single array literal.
Thus, when I&amp;rsquo;m passing a &lt;code&gt;pq.StringArray&lt;/code&gt;, it only works with the array function.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I found this out going through &lt;a href=&#34;https://github.com/lib/pq&#34;&gt;lib/pq&lt;/a&gt;&amp;rsquo;s issues,
finding &lt;a href=&#34;https://github.com/lib/pq/issues/600&#34;&gt;this issue&lt;/a&gt; with &lt;a href=&#34;https://github.com/lib/pq/issues/600#issuecomment-294143990&#34;&gt;this comment&lt;/a&gt; explaining the difference quite well,
which also pointed to a &lt;a href=&#34;https://github.com/lib/pq/issues/515&#34;&gt;simpler case&lt;/a&gt; where &lt;a href=&#34;https://github.com/lib/pq/issues/515#issuecomment-252393112&#34;&gt;this comment&lt;/a&gt; cleared things up for me.&lt;/p&gt;
</description>
      <source:markdown><p>I still feel rather new to PostgreSQL,
and a few times now in Go I&rsquo;ve tried to do something along the lines of:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">pgdb</span><span class="w"> </span><span class="kd">struct</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="nx">db</span><span class="w"> </span><span class="o">*</span><span class="nx">sql</span><span class="p">.</span><span class="nx">DB</span><span class="w">
</span></span></span><span class="line"><span class="cl"><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="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">db</span><span class="w"> </span><span class="o">*</span><span class="nx">pgdb</span><span class="p">)</span><span class="w"> </span><span class="nf">getEntityByID</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span><span class="w"> </span><span class="nx">ids</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">([]</span><span class="nx">Entity</span><span class="p">,</span><span class="w"> </span><span class="kt">error</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="nx">query</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&#34;SELECT * FROM entities WHERE entities.id IN ($1)&#34;</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="nx">rows</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">db</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">QueryContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="nx">query</span><span class="p">,</span><span class="w"> </span><span class="nx">pq</span><span class="p">.</span><span class="nf">StringArray</span><span class="p">(</span><span class="nx">ids</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="cp">/// ...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>But the query would always fail or retrieve no rows.
I&rsquo;ve always fixed it by switching the <code>IN $1</code> for a <code>= ANY($1)</code>,
but never quite understood why.</p>
<p>Researching this a bit more today,
I realized that the <a href="https://www.postgresql.org/docs/current/functions-comparisons.html#FUNCTIONS-COMPARISONS-IN-SCALAR"><code>IN</code></a> function takes a list of literals,
whereas <a href="https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.30.16"><code>ANY</code></a> is an array function that takes a single array literal.
Thus, when I&rsquo;m passing a <code>pq.StringArray</code>, it only works with the array function.</p>
<hr>
<p>I found this out going through <a href="https://github.com/lib/pq">lib/pq</a>&rsquo;s issues,
finding <a href="https://github.com/lib/pq/issues/600">this issue</a> with <a href="https://github.com/lib/pq/issues/600#issuecomment-294143990">this comment</a> explaining the difference quite well,
which also pointed to a <a href="https://github.com/lib/pq/issues/515">simpler case</a> where <a href="https://github.com/lib/pq/issues/515#issuecomment-252393112">this comment</a> cleared things up for me.</p>
</source:markdown>
    </item>
    
    <item>
      <title>Go&#39;s package fmt %q verb for strings</title>
      <link>https://stefan.vanburen.xyz/til/gofmt-q/</link>
      <pubDate>Thu, 23 Sep 2021 10:00:45 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/gofmt-q/</guid>
      <description>&lt;p&gt;I wasn&amp;rsquo;t aware of the Go &lt;code&gt;fmt&lt;/code&gt; package &lt;code&gt;%q&lt;/code&gt; verb, for quoting strings.
Typically, I&amp;rsquo;ve been escaping the quotes manually and using the &lt;code&gt;%s&lt;/code&gt; verb:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Sprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;this needs quoting: \&amp;#34;%s\&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;input&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But the &lt;code&gt;%q&lt;/code&gt; verb obviates the need for that manual quoting.&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&#34;https://pkg.go.dev/fmt&#34;&gt;package documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;%s    the uninterpreted bytes of the string or slice&lt;/p&gt;
&lt;p&gt;%q    a double-quoted string safely escaped with Go syntax&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And a quick example (on the &lt;a href=&#34;https://play.golang.org/p/w-DfnVMSi_k&#34;&gt;Go Playground&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;I&amp;#39;m a test string&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;\&amp;#34;%s\&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Output: &amp;#34;I&amp;#39;m a test string&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%q&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Output: &amp;#34;I&amp;#39;m a test string&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <source:markdown><p>I wasn&rsquo;t aware of the Go <code>fmt</code> package <code>%q</code> verb, for quoting strings.
Typically, I&rsquo;ve been escaping the quotes manually and using the <code>%s</code> verb:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;this needs quoting: \&#34;%s\&#34;&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;input&#34;</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p>But the <code>%q</code> verb obviates the need for that manual quoting.</p>
<p>From the <a href="https://pkg.go.dev/fmt">package documentation</a>:</p>
<blockquote>
<p>%s    the uninterpreted bytes of the string or slice</p>
<p>%q    a double-quoted string safely escaped with Go syntax</p>
</blockquote>
<p>And a quick example (on the <a href="https://play.golang.org/p/w-DfnVMSi_k">Go Playground</a>):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">main</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="kn">import</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="s">&#34;fmt&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><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="kd">func</span><span class="w"> </span><span class="nf">main</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="nx">test</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&#34;I&#39;m a test string&#34;</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="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;\&#34;%s\&#34;&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">test</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="c1">// Output: &#34;I&#39;m a test string&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;%q&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">test</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="c1">// Output: &#34;I&#39;m a test string&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div></source:markdown>
    </item>
    
    <item>
      <title>Go Templates Whitespace</title>
      <link>https://stefan.vanburen.xyz/til/go-templates-whitespace/</link>
      <pubDate>Tue, 31 Aug 2021 18:41:20 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/go-templates-whitespace/</guid>
      <description>&lt;p&gt;When writing HTML templates in Go, knowing about the &lt;a href=&#34;https://pkg.go.dev/text/template#hdr-Text_and_spaces&#34;&gt;whitespace modifiers&lt;/a&gt; is crucial for keeping both the templates and the output HTML looking good.&lt;/p&gt;
&lt;p&gt;For example, if you had the following template, with &lt;code&gt;.SomeText&lt;/code&gt; being &lt;code&gt;&amp;quot;foo&amp;quot;&lt;/code&gt; and &lt;code&gt;.Something&lt;/code&gt; being &lt;code&gt;true&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go-html-template&#34; data-lang=&#34;go-html-template&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/posts&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Something&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Text
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Image
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.SomeText&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The actual output HTML would look something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/posts&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; Text &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; foo &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which isn&amp;rsquo;t what you want, because there&amp;rsquo;s extra spaces &amp;mdash; both around &amp;ldquo;Text&amp;rdquo; and around &amp;ldquo;foo&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Instead, you could do:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go-html-template&#34; data-lang=&#34;go-html-template&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/posts&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.Something&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;cp&#34;&gt;{{-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Text&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;-}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;cp&#34;&gt;{{-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Image&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;-}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;cp&#34;&gt;{{-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.SomeText&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;-}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;to get&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/posts&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Text&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;foo&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which makes both the source code and HTML nice and neat.&lt;/p&gt;
</description>
      <source:markdown><p>When writing HTML templates in Go, knowing about the <a href="https://pkg.go.dev/text/template#hdr-Text_and_spaces">whitespace modifiers</a> is crucial for keeping both the templates and the output HTML looking good.</p>
<p>For example, if you had the following template, with <code>.SomeText</code> being <code>&quot;foo&quot;</code> and <code>.Something</code> being <code>true</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go-html-template" data-lang="go-html-template"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/posts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="cp">{{</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="na">.Something</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">  Text
</span></span><span class="line"><span class="cl">  <span class="cp">{{</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">  Image
</span></span><span class="line"><span class="cl">  <span class="cp">{{</span><span class="w"> </span><span class="k">end</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="cp">{{</span><span class="w"> </span><span class="na">.SomeText</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The actual output HTML would look something like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/posts&#34;</span><span class="p">&gt;&lt;</span><span class="nt">span</span><span class="p">&gt;</span> Text <span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span> foo <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Which isn&rsquo;t what you want, because there&rsquo;s extra spaces &mdash; both around &ldquo;Text&rdquo; and around &ldquo;foo&rdquo;.</p>
<p>Instead, you could do:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go-html-template" data-lang="go-html-template"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/posts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="cp">{{</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="na">.Something</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">  <span class="cp">{{-</span><span class="w"> </span><span class="nx">Text</span><span class="w"> </span><span class="cp">-}}</span>
</span></span><span class="line"><span class="cl">  <span class="cp">{{</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">  <span class="cp">{{-</span><span class="w"> </span><span class="nx">Image</span><span class="w"> </span><span class="cp">-}}</span>
</span></span><span class="line"><span class="cl">  <span class="cp">{{</span><span class="w"> </span><span class="k">end</span><span class="w"> </span><span class="cp">}}</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="cp">{{-</span><span class="w"> </span><span class="na">.SomeText</span><span class="w"> </span><span class="cp">-}}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>to get</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/posts&#34;</span><span class="p">&gt;&lt;</span><span class="nt">span</span><span class="p">&gt;</span>Text<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>foo<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Which makes both the source code and HTML nice and neat.</p>
</source:markdown>
    </item>
    
    <item>
      <title>time.Ticker in Go</title>
      <link>https://stefan.vanburen.xyz/til/ticker/</link>
      <pubDate>Fri, 21 May 2021 20:25:49 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/ticker/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://pkg.go.dev/time#Ticker&#34;&gt;&lt;code&gt;time.Ticker&lt;/code&gt;&lt;/a&gt; type in Go is incredibly useful for situations in which &lt;a href=&#34;https://en.wikipedia.org/wiki/Polling_(computer_science)&#34;&gt;polling&lt;/a&gt; is needed.&lt;/p&gt;
&lt;p&gt;The easiest way to use the Ticker is via the &lt;a href=&#34;https://pkg.go.dev/time#example-Tick&#34;&gt;&lt;code&gt;time.Tick&lt;/code&gt;&lt;/a&gt; function,
which just provides access to the ticking channel,
which makes it easy to &lt;code&gt;range&lt;/code&gt; over:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;currentTime&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;range&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Tick&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Second&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;		&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;current time: &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;currentTime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For more control, &lt;a href=&#34;https://pkg.go.dev/time#NewTicker&#34;&gt;&lt;code&gt;time.NewTicker&lt;/code&gt;&lt;/a&gt; works wonders &amp;mdash;
there&amp;rsquo;s no better example than the one &lt;a href=&#34;https://go.dev/play/p/nG23A6LEd19&#34;&gt;from the docs&lt;/a&gt;!&lt;/p&gt;
</description>
      <source:markdown><p>The <a href="https://pkg.go.dev/time#Ticker"><code>time.Ticker</code></a> type in Go is incredibly useful for situations in which <a href="https://en.wikipedia.org/wiki/Polling_(computer_science)">polling</a> is needed.</p>
<p>The easiest way to use the Ticker is via the <a href="https://pkg.go.dev/time#example-Tick"><code>time.Tick</code></a> function,
which just provides access to the ticking channel,
which makes it easy to <code>range</code> over:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">main</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="kn">import</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="s">&#34;fmt&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="s">&#34;time&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><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="kd">func</span><span class="w"> </span><span class="nf">main</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="k">for</span><span class="w"> </span><span class="nx">currentTime</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nf">Tick</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</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="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;current time: &#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">currentTime</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="p">}</span><span class="w">
</span></span></span></code></pre></div><p>For more control, <a href="https://pkg.go.dev/time#NewTicker"><code>time.NewTicker</code></a> works wonders &mdash;
there&rsquo;s no better example than the one <a href="https://go.dev/play/p/nG23A6LEd19">from the docs</a>!</p>
</source:markdown>
    </item>
    
    <item>
      <title>run vs errgroup</title>
      <link>https://stefan.vanburen.xyz/til/errgroup-vs-run/</link>
      <pubDate>Tue, 11 May 2021 10:38:26 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/errgroup-vs-run/</guid>
      <description>&lt;p&gt;I typically don&amp;rsquo;t do much with concurrency in Go, but messed around this morning with both &lt;a href=&#34;https://github.com/oklog/run&#34;&gt;oklog/run&lt;/a&gt; and &lt;a href=&#34;https://golang.org/x/sync/errgroup&#34;&gt;sync/errgroup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve defaulted to using oklog/run in the past, but I realized that while they have similar interfaces, they&amp;rsquo;re useful for different things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;oklog/run is useful for long-running processes.
&lt;ul&gt;
&lt;li&gt;think starting up http servers alongside other components, and waiting for one to finish, in which case all other components are signalled to finish.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;sync/errgroup is useful for short-lived, parallel processes.
&lt;ul&gt;
&lt;li&gt;think units of work to be done in parallel, where one process resulting in an error should stop the entire computation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
      <source:markdown><p>I typically don&rsquo;t do much with concurrency in Go, but messed around this morning with both <a href="https://github.com/oklog/run">oklog/run</a> and <a href="https://golang.org/x/sync/errgroup">sync/errgroup</a>.</p>
<p>I&rsquo;ve defaulted to using oklog/run in the past, but I realized that while they have similar interfaces, they&rsquo;re useful for different things:</p>
<ul>
<li>oklog/run is useful for long-running processes.
<ul>
<li>think starting up http servers alongside other components, and waiting for one to finish, in which case all other components are signalled to finish.</li>
</ul>
</li>
<li>sync/errgroup is useful for short-lived, parallel processes.
<ul>
<li>think units of work to be done in parallel, where one process resulting in an error should stop the entire computation.</li>
</ul>
</li>
</ul>
</source:markdown>
    </item>
    
    <item>
      <title>Use jq to see if a JSON key exists</title>
      <link>https://stefan.vanburen.xyz/til/jq-key-exists/</link>
      <pubDate>Thu, 22 Apr 2021 11:11:03 -0400</pubDate>
      <guid>https://stefan.vanburen.xyz/til/jq-key-exists/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m constantly using &lt;a href=&#34;https://stedolan.github.io/jq/&#34;&gt;&lt;code&gt;jq&lt;/code&gt;&lt;/a&gt; to deal with JSON via the CLI.&lt;/p&gt;
&lt;p&gt;Today I needed to figure out the difference between a key existing with a &lt;code&gt;null&lt;/code&gt; value or not existing at all in a bit of JSON.&lt;/p&gt;
&lt;p&gt;By default, &amp;ldquo;querying&amp;rdquo; a key via &lt;code&gt;jq&lt;/code&gt; will return &lt;code&gt;null&lt;/code&gt; whether the key exists and is &lt;code&gt;null&lt;/code&gt;, &lt;strong&gt;or&lt;/strong&gt; the key doesn&amp;rsquo;t exist:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fish&#34; data-lang=&#34;fish&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;△ &lt;span class=&#34;c&#34;&gt;# NOTE: the following is in fish, but should be straightforward to port to other shells
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;△ set &lt;span class=&#34;nv&#34;&gt;json&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;{&amp;#34;test&amp;#34;: null}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;△ echo &lt;span class=&#34;nv&#34;&gt;$json&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;jq&lt;/span&gt; .test
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;△ echo &lt;span class=&#34;nv&#34;&gt;$json&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;jq&lt;/span&gt; .nonexistent
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instead, you can use the &lt;code&gt;jq&lt;/code&gt;&amp;rsquo;s &lt;a href=&#34;https://stedolan.github.io/jq/manual/#has(key)&#34;&gt;&lt;code&gt;has&lt;/code&gt;&lt;/a&gt; function to determine the difference:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fish&#34; data-lang=&#34;fish&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;△ echo &lt;span class=&#34;nv&#34;&gt;$json&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;jq&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;has(&amp;#34;test&amp;#34;)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;△ echo &lt;span class=&#34;nv&#34;&gt;$json&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;jq&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;has(&amp;#34;nonexistent&amp;#34;)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <source:markdown><p>I&rsquo;m constantly using <a href="https://stedolan.github.io/jq/"><code>jq</code></a> to deal with JSON via the CLI.</p>
<p>Today I needed to figure out the difference between a key existing with a <code>null</code> value or not existing at all in a bit of JSON.</p>
<p>By default, &ldquo;querying&rdquo; a key via <code>jq</code> will return <code>null</code> whether the key exists and is <code>null</code>, <strong>or</strong> the key doesn&rsquo;t exist:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fish" data-lang="fish"><span class="line"><span class="cl">△ <span class="c"># NOTE: the following is in fish, but should be straightforward to port to other shells
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">△ set <span class="nv">json</span> <span class="s1">&#39;{&#34;test&#34;: null}&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">△ echo <span class="nv">$json</span> <span class="o">|</span> <span class="nf">jq</span> .test
</span></span><span class="line"><span class="cl"><span class="nf">null</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">△ echo <span class="nv">$json</span> <span class="o">|</span> <span class="nf">jq</span> .nonexistent
</span></span><span class="line"><span class="cl"><span class="nf">null</span>
</span></span></code></pre></div><p>Instead, you can use the <code>jq</code>&rsquo;s <a href="https://stedolan.github.io/jq/manual/#has(key)"><code>has</code></a> function to determine the difference:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fish" data-lang="fish"><span class="line"><span class="cl">△ echo <span class="nv">$json</span> <span class="o">|</span> <span class="nf">jq</span> <span class="s1">&#39;has(&#34;test&#34;)&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">true</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">△ echo <span class="nv">$json</span> <span class="o">|</span> <span class="nf">jq</span> <span class="s1">&#39;has(&#34;nonexistent&#34;)&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">false</span>
</span></span></code></pre></div></source:markdown>
    </item>
    
  </channel>
</rss>
