<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>staticnotes.org</title>
    <link>/</link>
    <description>Recent TILs from Rob on staticnotes.org</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-US</language>
    <lastBuildDate>Sun, 18 Jan 2026 20:00:00 +0000</lastBuildDate><atom:link href="/index.xml" rel="self" type="application/rss+xml" /><image>
      <url>https://staticnotes.org/favicon.ico</url>
      <title>staticnotes.org</title>
    </image>
    
    
    <item>
      <title>TIL how to set up multiple SSH keys (for multiple Github accounts)</title>
      <link>/til/2025/11/how-to-set-up-multiple-ssh-keys/</link>
      <pubDate>Fri, 28 Nov 2025 16:20:00 +0000</pubDate>
      
      <guid>/til/2025/11/how-to-set-up-multiple-ssh-keys/</guid>
    <description>&lt;p&gt;Setting up SSH keys is one of these things I need to do every couple of months. Inevitably, I don&amp;rsquo;t remember how to do it and then follow some tutorial, e.g. the &#xA;&lt;a href=&#34;https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;Github Docs&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;. It kind of always works but I haven&amp;rsquo;t fully internalized how to properly manage those different SSH keys.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: This learning was provoked by setting up multiple SSH keys for different Github accounts (I know how to do that) and then being able to &lt;code&gt;git clone {private-repository}&lt;/code&gt; a private repository with the correct ssh key (I didn&amp;rsquo;t know how to do that). An example use case could be a personal and professional Github account that don&amp;rsquo;t have access to the same private repositories. So ideally when we git clone we want to automatically pick the right ssh key.&lt;/p&gt;&#xA; &lt;h3 id=&#34;1-generate-the-ssh-keys-for-each-account&#34;&gt;&#xA;  &lt;a href=&#34;#1-generate-the-ssh-keys-for-each-account&#34; class=&#34;header-link&#34;&gt;&#xA;    1. Generate the SSH keys for each account&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;Let&amp;rsquo;s assume we want to generate new separate ssh keys for each account. I like to have them all in my &lt;code&gt;~/.ssh&lt;/code&gt; folder.&#xA;We can use the key generation command&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ~/.ssh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ssh-keygen -t ed25519 -C &lt;span class=&#34;s2&#34;&gt;&amp;#34;your_email or your_name&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where we specify the encryption type (&lt;code&gt;-t&lt;/code&gt;) as &lt;code&gt;ed25519&lt;/code&gt; which is &#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/EdDSA#Ed25519&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;Edwards-curve Digital Signature Algorithm&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;                style=&#34;height: 0.7em; width: 0.7em; margin-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;                class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;                viewBox=&#34;0 0 640 512&#34;&gt;&#xA;                &lt;path fill=&#34;currentColor&#34;&#xA;                    d=&#34;M640 51.2l-.3 12.2c-28.1 .8-45 15.8-55.8 40.3-25 57.8-103.3 240-155.3 358.6H415l-81.9-193.1c-32.5 63.6-68.3 130-99.2 193.1-.3 .3-15 0-15-.3C172 352.3 122.8 243.4 75.8 133.4 64.4 106.7 26.4 63.4 .2 63.7c0-3.1-.3-10-.3-14.2h161.9v13.9c-19.2 1.1-52.8 13.3-43.3 34.2 21.9 49.7 103.6 240.3 125.6 288.6 15-29.7 57.8-109.2 75.3-142.8-13.9-28.3-58.6-133.9-72.8-160-9.7-17.8-36.1-19.4-55.8-19.7V49.8l142.5 .3v13.1c-19.4 .6-38.1 7.8-29.4 26.1 18.9 40 30.6 68.1 48.1 104.7 5.6-10.8 34.7-69.4 48.1-100.8 8.9-20.6-3.9-28.6-38.6-29.4 .3-3.6 0-10.3 .3-13.6 44.4-.3 111.1-.3 123.1-.6v13.6c-22.5 .8-45.8 12.8-58.1 31.7l-59.2 122.8c6.4 16.1 63.3 142.8 69.2 156.7L559.2 91.8c-8.6-23.1-36.4-28.1-47.2-28.3V49.6l127.8 1.1 .2 .5z&#34;&gt;&#xA;                &lt;/path&gt;&#xA;            &lt;/svg&gt;&#xA;        &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; and generally &#xA;&lt;a href=&#34;https://www.latacora.com/blog/cryptographic-right-answers/&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;recommended over RSA-based keys&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;. The comment (&lt;code&gt;-C&lt;/code&gt;) argument allows us to optionally add a comment that is added at the back of the key so that you remember who it created. People often use their email address. However, this is not used anywhere to select the key.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ Generating public/private ed25519 key pair.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ Enter file in which to save the key &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;/Users/youruser/.ssh/id_ed25519&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: /Users/youruser/.ssh/github_personal&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ Enter passphrase &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;github_personal&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;empty &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; no passphrase&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This generates both the private and public key &lt;code&gt;github_personal&lt;/code&gt; (private) and &lt;code&gt;github_personal.pub&lt;/code&gt; (public) in the specified path. If we entered a passphrase the private key will be encrypted as well using &#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Triple_DES&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;3DES&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;                style=&#34;height: 0.7em; width: 0.7em; margin-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;                class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;                viewBox=&#34;0 0 640 512&#34;&gt;&#xA;                &lt;path fill=&#34;currentColor&#34;&#xA;                    d=&#34;M640 51.2l-.3 12.2c-28.1 .8-45 15.8-55.8 40.3-25 57.8-103.3 240-155.3 358.6H415l-81.9-193.1c-32.5 63.6-68.3 130-99.2 193.1-.3 .3-15 0-15-.3C172 352.3 122.8 243.4 75.8 133.4 64.4 106.7 26.4 63.4 .2 63.7c0-3.1-.3-10-.3-14.2h161.9v13.9c-19.2 1.1-52.8 13.3-43.3 34.2 21.9 49.7 103.6 240.3 125.6 288.6 15-29.7 57.8-109.2 75.3-142.8-13.9-28.3-58.6-133.9-72.8-160-9.7-17.8-36.1-19.4-55.8-19.7V49.8l142.5 .3v13.1c-19.4 .6-38.1 7.8-29.4 26.1 18.9 40 30.6 68.1 48.1 104.7 5.6-10.8 34.7-69.4 48.1-100.8 8.9-20.6-3.9-28.6-38.6-29.4 .3-3.6 0-10.3 .3-13.6 44.4-.3 111.1-.3 123.1-.6v13.6c-22.5 .8-45.8 12.8-58.1 31.7l-59.2 122.8c6.4 16.1 63.3 142.8 69.2 156.7L559.2 91.8c-8.6-23.1-36.4-28.1-47.2-28.3V49.6l127.8 1.1 .2 .5z&#34;&gt;&#xA;                &lt;/path&gt;&#xA;            &lt;/svg&gt;&#xA;        &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;. We can check out what the keys look like:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat github_personal.pub&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDycaSFXnekEe32AZFhhDp3Q14JRXF7bu8CNfGf7Z6hN your_email &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ cat github_personal&#xA;&#xA;-----BEGIN OPENSSH PRIVATE KEY-----&#xA;somegibberylongkeyperhapsfurtherencryptedusingpassphrase&#xA;-----END OPENSSH PRIVATE KEY-----&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let&amp;rsquo;s also use the same method to create a keypair for work (&lt;code&gt;github_work&lt;/code&gt;, &lt;code&gt;github_work.pub&lt;/code&gt;). Once we have these keys, we can add them to our two Github accounts.&lt;/p&gt;&#xA; &lt;h3 id=&#34;2-associate-the-public-keys-with-the-github-accounts&#34;&gt;&#xA;  &lt;a href=&#34;#2-associate-the-public-keys-with-the-github-accounts&#34; class=&#34;header-link&#34;&gt;&#xA;    2. Associate the public keys with the Github accounts&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;In both Github accounts, navigate to &lt;code&gt;Access:SSH and GPG Keys&lt;/code&gt; -&amp;gt; &lt;code&gt;New SSH key&lt;/code&gt; and add the &lt;strong&gt;public key&lt;/strong&gt; as an &lt;em&gt;Authentication Key&lt;/em&gt; to the account. Github now has the ability to verify messages that were signed by the corresponding private key of the pair.&lt;/p&gt;&#xA; &lt;h3 id=&#34;3-set-up-openssh-client-config-file&#34;&gt;&#xA;  &lt;a href=&#34;#3-set-up-openssh-client-config-file&#34; class=&#34;header-link&#34;&gt;&#xA;    3. Set up OpenSSH client config file&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;The file &lt;code&gt;~/.ssh/config&lt;/code&gt; allows us to configure &amp;ldquo;Host&amp;rdquo; specifications that we can refer to when using SSH (e.g. when git clone uses the SSH protocol for data transfer). The file looks like this:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Host hostname1&#xA;    SSH_OPTION value&#xA;    SSH_OPTION value&#xA;&#xA;Host hostname2&#xA;    SSH_OPTION value&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In our case, we define the two different github identities that we want to be able to select:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Host github-personal&#xA;    User git&#xA;    PreferredAuthentications publickey&#xA;    Hostname github.com&#xA;    IdentityFile ~/.ssh/github_personal&#xA;&#xA;Host github-work&#xA;    User git&#xA;    PreferredAuthentications publickey&#xA;    Hostname github.com&#xA;    IdentityFile ~/.ssh/github_work&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This defines which keys to use when we connect using SSH via &lt;code&gt;user@host&lt;/code&gt;. So when we the test the config by running &lt;code&gt;ssh -T git@github-personal&lt;/code&gt; SSH will use the SSH key &lt;code&gt;~/.ssh/github_personal&lt;/code&gt; as specified in the file. (Note: We can name the host and user whatever we want.)&lt;/p&gt;&#xA; &lt;h3 id=&#34;4-use-the-right-hostname-when-cloning-repositories&#34;&gt;&#xA;  &lt;a href=&#34;#4-use-the-right-hostname-when-cloning-repositories&#34; class=&#34;header-link&#34;&gt;&#xA;    4. Use the right hostname when cloning repositories&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;Let&amp;rsquo;s say we want to git clone a repository that only our work account has access to, then I can use the git clone command &lt;code&gt;git clone {user}/{host}:{repo_path}.git&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ git clone git@github-work:/org1/project1.git&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;or more explicitely:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ git clone ssh://git@github-work/org1/project.git&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;git/ssh will look into the &lt;code&gt;config&lt;/code&gt; file and select the configured private key for the provided host.&lt;/p&gt;&#xA;&lt;p&gt;GitHub will send a challenge (message) to our machine for authentication. The private key will be used to sign this challenge and our machine then sends the signed message back to the Github server. The Github server will use the stored public key (from step 2) to verify the signature and allow a connection.&lt;/p&gt;&#xA;&lt;p&gt;Note: If in step 1) we decided to encrypt the private key with a passphrase we will be prompted to provide it. Normally, at that point MacOS will offer us to add this passphrase to our &#xA;&lt;a href=&#34;https://support.apple.com/en-gb/guide/keychain-access/welcome/mac&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;Keychain&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL how to re-run only failed tests</title>
      <link>/til/2025/11/pytest-rerun-failed/</link>
      <pubDate>Fri, 21 Nov 2025 13:00:00 +0000</pubDate>
      
      <guid>/til/2025/11/pytest-rerun-failed/</guid>
    <description>&lt;p&gt;This is a super small thing I stumbled over.&#xA;When I implement a new feature, there is inevitably a step where I go through the failing pytest tests and fix or clarify them.&lt;/p&gt;&#xA;&lt;p&gt;Unless I use an IDE, my work loop is like this:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Make code change&lt;/li&gt;&#xA;&lt;li&gt;Run &lt;code&gt;python -m pytest&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Check which tests are failing.&lt;/li&gt;&#xA;&lt;li&gt;Go back to 1.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Now, 2. runs all tests which can take quite some time. There is always the option to run a specific test only, but multiple failing tests can be scattered across different files.&lt;/p&gt;&#xA;&lt;p&gt;So instead, what you can do is to only run the tests that failed at your last test run. Simply use:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m pytest --last-failed&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once you have fixed those tests, it&amp;rsquo;s worth running all tests one more time to check that nothing else was broken by the new changes.&lt;/p&gt;&#xA;&lt;p&gt;Another option is to use the test view of your IDE, if you have access to one in that environment.&lt;/p&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL how to investigate missing data easily with DuckDB</title>
      <link>/til/2025/05/duckdb-glob_utility_function/</link>
      <pubDate>Fri, 16 May 2025 14:00:00 +0000</pubDate>
      
      <guid>/til/2025/05/duckdb-glob_utility_function/</guid>
    <description>&lt;p&gt;In data engineering pipelines we commonly store output data in S3 buckets at various stages.&#xA;In this particular case we stored the input data received from customers as csv files in the S3 bucket &lt;code&gt;s3://customer-ingested/customerA.csv&lt;/code&gt; and after some transformations we stored the transformed data as csv files in another S3 bucket &lt;code&gt;s3://customer-transformed/customerA.csv&lt;/code&gt;.&lt;/p&gt;&#xA; &lt;h3 id=&#34;problem&#34;&gt;&#xA;  &lt;a href=&#34;#problem&#34; class=&#34;header-link&#34;&gt;&#xA;    Problem&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;For some of the customers the csv file was missing in the first bucket &lt;code&gt;customer-ingested&lt;/code&gt; while we were sure that all customers had a file in &lt;code&gt;customer-transformed&lt;/code&gt;. However, there was a legit reason why the file could be missing which was that in the application the customer had a state of &lt;code&gt;is_deactivated = True&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The goal of this investigation was to find all the active customers for which we were missing data in the bucket &lt;code&gt;customer-ingested&lt;/code&gt;.&lt;/p&gt;&#xA; &lt;h3 id=&#34;solution&#34;&gt;&#xA;  &lt;a href=&#34;#solution&#34; class=&#34;header-link&#34;&gt;&#xA;    Solution&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;The nice thing about DuckDB in this scenario is that I can combine filesystem data with information from an application table and work in (familiar) SQL land.&lt;/p&gt;&#xA;&lt;p&gt;Here is the query:&lt;/p&gt;&#xA;&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;k&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;transformed&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&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;&#xA;&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;&#x9;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;select&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regexp_extract&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&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;s1&#34;&gt;&amp;#39;/([^/]+)\.csv$&amp;#39;&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;1&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;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filenames_transformed&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;glob&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;s3://customer-transformed/*.csv&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;&#x9;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;n&#34;&gt;ingested&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&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;&#xA;&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;&#x9;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;select&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regexp_extract&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&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;s1&#34;&gt;&amp;#39;/([^/]+)\.csv$&amp;#39;&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;1&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;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filenames_ingested&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;glob&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;s3://customer-ingested/*.csv&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;&#x9;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;n&#34;&gt;customer_status&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&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;&#xA;&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;&#x9;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;select&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;customer_name&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;n&#34;&gt;is_deactivated&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read_parquet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;s3://application_table_snapshot/customers.parquet&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;&#xA;&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;&#xA;&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;select&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;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;transformed&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;left&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ingested&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;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;transformed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filenames_transformed&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;ingested&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filenames_ingested&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;left&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;customer_status&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cs&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;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;transformed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filenames_transformed&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;cs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;customer_name&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;where&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_deactivated&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;False&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;and&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filenames_ingested&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;is&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌───────────────────────┬────────────────────┬────────────────────┬────────────────┐&#xA;│ filenames_transformed │ filenames_ingested │   customer_name    │ is_deactivated │&#xA;│        varchar        │      varchar       │      varchar       │    varchar     │&#xA;├───────────────────────┼────────────────────┼────────────────────┼────────────────┤&#xA;│ customerT             │ NULL               │ customerT          │ False          │&#xA;│ customerW             │ NULL               │ customerW          │ False          │&#xA;│ customerZ             │ NULL               │ customerZ          │ False          │&#xA;└───────────────────────┴────────────────────┴────────────────────┴────────────────┘&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the CTE, I am creating a table &lt;code&gt;transformed&lt;/code&gt; with all the filenames in the S3 bucket &lt;code&gt;customer-transformed&lt;/code&gt;. I am using DuckDB&amp;rsquo;s utility function &lt;code&gt;glob(search_path)&lt;/code&gt; to retrieve the filenames. I do the same for the bucket &lt;code&gt;customer-ingested&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;To get the customer status I read from a recent replication snapshot of the application database to get &lt;code&gt;customer_status&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Finally, I join the three expressions to identify missing files (missing values) in the column &lt;code&gt;filenames_ingested&lt;/code&gt; for active customers.&lt;/p&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL that DuckDB now supports Avro files</title>
      <link>/til/2025/03/duckdb-avro-support/</link>
      <pubDate>Wed, 12 Mar 2025 16:00:00 +0000</pubDate>
      
      <guid>/til/2025/03/duckdb-avro-support/</guid>
    <description>&lt;p&gt;In the data engineering pipelines of my current company we use two main file formats:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Parquet files for analytical workloads (columnar-storage)&lt;/li&gt;&#xA;&lt;li&gt;Avro files for transactional / event-based messages (row-storage)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In &#xA;&lt;a href=&#34;/posts/duckdb-for-data-scientists/&#34; &#xA;&gt;Querying remote S3 files&#xA;&lt;/a&gt; I wrote about how I use DuckDB to query parquet files stored in S3. Recently, I noticed that DuckDB &#xA;&lt;a href=&#34;https://duckdb.org/2024/12/09/duckdb-avro-extension.html&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;started supporting&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; reading of &#xA;&lt;a href=&#34;https://avro.apache.org/&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;Avro&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; files in the same way.&lt;/p&gt;&#xA; &lt;h3 id=&#34;install-extension&#34;&gt;&#xA;  &lt;a href=&#34;#install-extension&#34; class=&#34;header-link&#34;&gt;&#xA;    Install extension&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;To install the extension open DuckDB and run:&lt;/p&gt;&#xA;&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;INSTALL&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;avro&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;community&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;LOAD&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;avro&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;h3 id=&#34;read-local-files&#34;&gt;&#xA;  &lt;a href=&#34;#read-local-files&#34; class=&#34;header-link&#34;&gt;&#xA;    Read local files&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;Local files can be queried with the &lt;code&gt;read_avro&lt;/code&gt; function:&lt;/p&gt;&#xA;&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;k&#34;&gt;select&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;FROM&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read_avro&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;my_dataset.avro&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;h3 id=&#34;read-files-stored-in-s3&#34;&gt;&#xA;  &lt;a href=&#34;#read-files-stored-in-s3&#34; class=&#34;header-link&#34;&gt;&#xA;    Read files stored in S3&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;Remote files can be queried by providing the S3 URI (after &#xA;&lt;a href=&#34;/posts/duckdb-for-data-scientists/#authentication-with-aws&#34; &#xA;&gt;logging into the AWS account&#xA;&lt;/a&gt;):&lt;/p&gt;&#xA;&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;k&#34;&gt;select&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;FROM&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read_avro&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;s3://my_bucket/my_remote_dataset.avro&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A few limitations of the extension are listed &#xA;&lt;a href=&#34;https://duckdb.org/2024/12/09/duckdb-avro-extension.html#limitations--next-steps&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;here&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL how to fix a broken Joplin sync</title>
      <link>/til/broken-joplin-sync/</link>
      <pubDate>Mon, 17 Feb 2025 00:00:00 +0000</pubDate>
      
      <guid>/til/broken-joplin-sync/</guid>
    <description>&lt;p&gt;I use &#xA;&lt;a href=&#34;https://joplinapp.org/&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;Joplin&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; for all my note-taking as it&amp;rsquo;s open-source, markdown-based, and has decent Desktop and Android apps. I use note encryption and sync my notes via WebDAV with my remote Nextcloud instance.&lt;/p&gt;&#xA; &lt;h3 id=&#34;problem&#34;&gt;&#xA;  &lt;a href=&#34;#problem&#34; class=&#34;header-link&#34;&gt;&#xA;    Problem&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;After not syncing my notes for several weeks, I encountered a couple of errors both on my Desktop app and on my Android app. I don&amp;rsquo;t have access to the error message anymore, but the errors referred to files and file IDs that caused inconsistencies on the remote server, e.g. broken references:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;f1231gdffgasd1asd2.md TypeError: Cannot read property &amp;#39;type_ of null.&#xA;&lt;/code&gt;&lt;/pre&gt; &lt;h3 id=&#34;solution&#34;&gt;&#xA;  &lt;a href=&#34;#solution&#34; class=&#34;header-link&#34;&gt;&#xA;    Solution&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;To solve the issue, I had to delete the offending file on the remote server. However, to not lose it, it&amp;rsquo;s best to make a local copy of the file&amp;rsquo;s content if it is present on one of your local devices.&lt;/p&gt;&#xA;&lt;p&gt;First, I had to determine which file caused the issue, which is a bit harder here as filenames are encrypted. The easiest way to identify the note from the filename is to paste a local markdown reference into a new Joplin note like this:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[Note I am looking for](:/f1231gdffgasd1asd2)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and then click the link in the rendered note. This took me to the offending note.&lt;/p&gt;&#xA;&lt;p&gt;Second, copy the content into a new note.&lt;/p&gt;&#xA;&lt;p&gt;Third, I had to delete the file on the remote. I connected on my Mac to the remote WebDAV server via Finder. In Finder, Click on &lt;code&gt;Go&lt;/code&gt; -&amp;gt; &lt;code&gt;Connect to Server&lt;/code&gt; -&amp;gt; Add address: &lt;code&gt;https://yourserveraddress.org/remote.php/webdav/joplin&lt;/code&gt; (look up the link in your Joplin settings), and authenticated with my Nextcloud credentials. Then I was able to search for the file &lt;code&gt;f1231gdffgasd1asd2&lt;/code&gt; and delete it.&lt;/p&gt;&#xA;&lt;p&gt;The sync now succeeds.&lt;/p&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL how to debug a broken nextcloud login (again)</title>
      <link>/til/nextcloud-login-debugging-2/</link>
      <pubDate>Sun, 16 Feb 2025 00:00:00 +0000</pubDate>
      
      <guid>/til/nextcloud-login-debugging-2/</guid>
    <description>&lt;p&gt;The symptoms of this problem were the same as the ones I described in &#xA;&lt;a href=&#34;/til/nextcloud-login-debugging/&#34; &#xA;&gt;TIL how to debug a broken nextcloud login&#xA;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;!-- /til/nextcloud-login-debugging/) --&gt;&#xA; &lt;h3 id=&#34;problem&#34;&gt;&#xA;  &lt;a href=&#34;#problem&#34; class=&#34;header-link&#34;&gt;&#xA;    Problem&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;Phone and Mac apps stopped syncing data with the Nextcloud instance. In my browser I could access the login page, but after entering the details I was being sent back to the same login page without any error message.&lt;/p&gt;&#xA; &lt;h3 id=&#34;investigation&#34;&gt;&#xA;  &lt;a href=&#34;#investigation&#34; class=&#34;header-link&#34;&gt;&#xA;    Investigation&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;Last time the issue was caused by excessive logging. However, I reduced the &lt;code&gt;loglevel&lt;/code&gt; in the nextcloud config, so this was not the issue here. I am no expert in web admin, PHP, or nextcloud, so I used Claude 3.5 to &lt;em&gt;pair&lt;/em&gt; on debugging:&lt;/p&gt;&#xA;&lt;div class=&#34;promptbox&#34;&gt;&#xA;    &lt;div class=&#34;promptbox-title&#34;&gt;&#xA;        Prompt&#xA;    &lt;/div&gt;&#xA;    &lt;div class=&#34;promptbox-content&#34;&gt;&#xA;        I am self-hosting a nextcloud instance on a Hetzner VPC. I currently have the following problem. I can&amp;rsquo;t log in to nextcloud via my account. The screen just reloads and shows me the login page again. It is not a login detail issue. They are correct. Moreover, other nextcloud related syncs (files, calendar) stopped working. Walk me through how I can debug this issue and get nextcloud up and running again.      &lt;/div&gt; &#xA;&lt;/div&gt;&#xA;&lt;p&gt;I can&amp;rsquo;t say that the suggestions worked right away, but they put me on the right path and helped me with some useful debugging commands.&lt;/p&gt;&#xA;&lt;p&gt;The command&lt;/p&gt;&#xA;&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;df -h&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;showed me that I didn&amp;rsquo;t have &lt;em&gt;any&lt;/em&gt; free space. While the command&lt;/p&gt;&#xA;&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;du -sh /var/www/nextcloud/data/*&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;indicated that in nextcloud a lot of space was occupied by old file versions and deleted files from the nextcloud file sync.&lt;/p&gt;&#xA; &lt;h3 id=&#34;solution&#34;&gt;&#xA;  &lt;a href=&#34;#solution&#34; class=&#34;header-link&#34;&gt;&#xA;    Solution&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;You can use the nextcloud console &lt;code&gt;occ&lt;/code&gt; (ownCloud Console) tool to run maintenance tasks on the nextcloud instance.&lt;/p&gt;&#xA;&lt;p&gt;The command&lt;/p&gt;&#xA;&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;sudo -u www-data php /var/www/nextcloud/occ list&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;lists all available commands.&lt;/p&gt;&#xA;&lt;p&gt;A couple of clean up commands to remove old file versions and files in the trashbin worked for me:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Check Nextcloud trashbin size&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo -u www-data php /var/www/nextcloud/occ trashbin:cleanup --all-users&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Clean up file versions&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo -u www-data php /var/www/nextcloud/occ versions:cleanup&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Clear Nextcloud cache:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo -u www-data php /var/www/nextcloud/occ cache:clear&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This freed up enough space for nextcloud to work again.&lt;/p&gt;&#xA;&lt;p&gt;Unfortunately, the &lt;code&gt;occ&lt;/code&gt; commands didn&amp;rsquo;t work right away because there was apparently not enough space to run any of them. Each one returned the same error message:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;fwrite(): write of 4963 bytes failed with errno=28 No space left on device &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So I first had to free up a few hundred megabytes:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Clear local repository of retrieved package files:&lt;/p&gt;&#xA;&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;sudo apt-get clean&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Remove old log files:&lt;/p&gt;&#xA;&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;sudo find /var/log -type f -name &lt;span class=&#34;s2&#34;&gt;&amp;#34;*.gz&amp;#34;&lt;/span&gt; -delete&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo find /var/log -type f -name &lt;span class=&#34;s2&#34;&gt;&amp;#34;*.1&amp;#34;&lt;/span&gt; -delete&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo truncate -s &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; /var/log/*.log&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Remove temporary files:&lt;/p&gt;&#xA;&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;sudo rm -rf /tmp/*&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This cleared enough space to run the &lt;code&gt;occ&lt;/code&gt; commands.&lt;/p&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL (from Claude) how to create separate RSS feeds for my hugo blog </title>
      <link>/til/hugo-with-separate-rss-feeds/</link>
      <pubDate>Thu, 03 Oct 2024 00:00:00 +0000</pubDate>
      
      <guid>/til/hugo-with-separate-rss-feeds/</guid>
    <description>&lt;p&gt;I really like the idea of providing different content types of my blog in separate RSS feeds. For example a blog could have:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;essays&lt;/li&gt;&#xA;&lt;li&gt;today-I-learned posts&lt;/li&gt;&#xA;&lt;li&gt;link-list or bloglink posts&lt;/li&gt;&#xA;&lt;li&gt;short social media style posts&lt;/li&gt;&#xA;&lt;li&gt;etc.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Providing different RSS feeds for them allows my readers to subscribe to all or a subset of these, depending on their interest. I am using hugo, as the static site generator for this website. Setting up these different feeds for a framework that I am only partially familar with is a great use-case to work with an LLM.&lt;/p&gt;&#xA;&lt;p&gt;I knew that I would need to:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Distinguish different content types with a flag&lt;/li&gt;&#xA;&lt;li&gt;Specify different RSS templates that filter on these flags&lt;/li&gt;&#xA;&lt;li&gt;Tell hugo to generate separate xml files for each content type and use the right templates.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;I just didn&amp;rsquo;t know how to piece these parts together. I first tried googling the answer and read the typical mix of&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;stackoverflow posts that were not solving the exact same problem&lt;/li&gt;&#xA;&lt;li&gt;hugo forum discussions that did not have a clear solution or where the solution wasn&amp;rsquo;t transferable to my unique setup.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I think with those first pointers, spending some time on the hugo documentation, and trial-and-erroring, I could have worked out how to do it.&#xA;I think that these shallow but unknown problems are the ideal use case for an LLM.&lt;/p&gt;&#xA;&lt;p&gt;I think of using LLMs as an interface for search + context, where I don&amp;rsquo;t have to take the laborious work of pre-filtering and connecting the sources. Instead, it helps me get a quick overview and a potential draft of a solution. I can then go deeper and understand the problem better by asking about parts of the solution that I don&amp;rsquo;t understand. I can then mix this with more googling and get to a solution.&lt;/p&gt;&#xA; &lt;h2 id=&#34;my-goal&#34;&gt;&#xA;  &lt;a href=&#34;#my-goal&#34; class=&#34;header-link&#34;&gt;&#xA;    My Goal:&#xA;  &lt;/a&gt;&#xA;&lt;/h2&gt;&lt;div class=&#34;promptbox&#34;&gt;&#xA;    &lt;div class=&#34;promptbox-title&#34;&gt;&#xA;        Prompt&#xA;    &lt;/div&gt;&#xA;    &lt;div class=&#34;promptbox-content&#34;&gt;&#xA;        &lt;p&gt;I have a hugo blog with the following folder structure:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/content/posts/post1.md&#xA;/content/posts/post2.md&#xA;/content/posts/_index.md&#xA;/content/til/_index.md&#xA;/content/til/til1.md&#xA;/content/til/til2.md&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Markdown pages written in the posts subfolder have type: post in the frontmatter and pages written in the til subfolder have type: til in the submatter.&lt;/p&gt;&#xA;&lt;p&gt;Explain to me step by step how I can create three separate rss feeds on my website.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Only showing content coming from the til subfolder on til.xml&lt;/li&gt;&#xA;&lt;li&gt;Only showing content coming from the post subfolder posts.xml&lt;/li&gt;&#xA;&lt;li&gt;One showing everything on index.xml&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;      &lt;/div&gt; &#xA;&lt;/div&gt;&#xA; &lt;h2 id=&#34;solution&#34;&gt;&#xA;  &lt;a href=&#34;#solution&#34; class=&#34;header-link&#34;&gt;&#xA;    Solution&#xA;  &lt;/a&gt;&#xA;&lt;/h2&gt;&lt;details class=&#34;llmbox llm-anthropic&#34;&gt;&#xA;    &lt;summary class=&#34;llmbox-title&#34;&gt;&#xA;        Model: claude-3-5-sonnet-20241022 - response &#xA;    &lt;/summary&gt;&#xA;    &lt;div class=&#34;llmbox-content&#34;&gt;&#xA;&lt;p&gt;I&amp;rsquo;d be happy to explain how you can create three separate RSS feeds for your Hugo blog with the structure you&amp;rsquo;ve described. Let&amp;rsquo;s go through this step-by-step:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Create RSS template files:&#xA;First, you&amp;rsquo;ll need to create three separate RSS template files in your Hugo project&amp;rsquo;s layouts folder.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Now, let me explain each step in more detail:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We create three separate RSS template files in the &lt;code&gt;layouts/_default/&lt;/code&gt; directory. Each file corresponds to one of the RSS feeds you want to create.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;In each RSS template, we use Hugo&amp;rsquo;s templating language to generate the RSS feed. The main difference between the templates is in the range statement:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;For &lt;code&gt;til.xml&lt;/code&gt;, we use &lt;code&gt;{{ range where .Site.RegularPages &amp;quot;Type&amp;quot; &amp;quot;til&amp;quot; }}&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;For &lt;code&gt;posts.xml&lt;/code&gt;, we use &lt;code&gt;{{ range where .Site.RegularPages &amp;quot;Type&amp;quot; &amp;quot;post&amp;quot; }}&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;For &lt;code&gt;index.xml&lt;/code&gt;, we use &lt;code&gt;{{ range .Site.RegularPages }}&lt;/code&gt; to include all content&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We update the Hugo configuration file to define new output formats for TIL and Posts, and to include these new formats in the home page outputs.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We add links to the new RSS feeds in the site&amp;rsquo;s HTML, typically in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section or footer.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Finally, we build the site to generate the new RSS feed files.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;After following these steps, your Hugo site will generate three separate RSS feeds:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;til.xml&lt;/code&gt; will only include content from the &lt;code&gt;til&lt;/code&gt; subfolder&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;posts.xml&lt;/code&gt; will only include content from the &lt;code&gt;posts&lt;/code&gt; subfolder&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;index.xml&lt;/code&gt; will include all content&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Would you like me to explain any part of this process in more detail?&#xA;&lt;/div&gt;&lt;/p&gt;&#xA;&lt;/details&gt;&#xA;&lt;p&gt;I followed these steps, except for using my already existing xml template for &lt;code&gt;til.xml&lt;/code&gt;, &lt;code&gt;posts.xml&lt;/code&gt;, &lt;code&gt;index.xml&lt;/code&gt;. I already read in some hugo discussions that I need to add &lt;code&gt;[outputs]&lt;/code&gt; and &lt;code&gt;[outputFormats]&lt;/code&gt; to my hugo &lt;code&gt;config.toml&lt;/code&gt; file. However, I didn&amp;rsquo;t really understand the difference between home, page, section and what exactly &lt;code&gt;home = [&amp;quot;HTML&amp;quot;, &amp;quot;RSS&amp;quot;, &amp;quot;JSON&amp;quot;, &amp;quot;TIL&amp;quot;, &amp;quot;POSTS&amp;quot;]&lt;/code&gt; does.&#xA;So I asked for clarification:&lt;/p&gt;&#xA;&lt;div class=&#34;promptbox&#34;&gt;&#xA;    &lt;div class=&#34;promptbox-title&#34;&gt;&#xA;        Prompt&#xA;    &lt;/div&gt;&#xA;    &lt;div class=&#34;promptbox-content&#34;&gt;&#xA;        Can you explain to me the config [outputs] and its purpose as well as [outputFormats]?      &lt;/div&gt; &#xA;&lt;/div&gt;&#xA;&lt;details class=&#34;llmbox llm-anthropic&#34;&gt;&#xA;    &lt;summary class=&#34;llmbox-title&#34;&gt;&#xA;        Model: claude-3-5-sonnet-20241022 - response &#xA;    &lt;/summary&gt;&#xA;    &lt;div class=&#34;llmbox-content&#34;&gt;&#xA;&lt;p&gt;Certainly! I&amp;rsquo;d be happy to explain the &lt;code&gt;[outputs]&lt;/code&gt; and &lt;code&gt;[outputFormats]&lt;/code&gt; configurations in Hugo and their purposes.&lt;/p&gt;&#xA;&lt;p&gt;Now, let me provide a more detailed explanation of these configurations:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;code&gt;[outputs]&lt;/code&gt;: This configuration section determines what types of files Hugo will generate for different types of pages on your site. In our case, we&amp;rsquo;re telling Hugo to generate additional output formats for the home page. The line &lt;code&gt;home = [&amp;quot;HTML&amp;quot;, &amp;quot;RSS&amp;quot;, &amp;quot;TIL&amp;quot;, &amp;quot;POSTS&amp;quot;]&lt;/code&gt; means:&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;For the home page, generate the standard HTML and RSS outputs&lt;/li&gt;&#xA;&lt;li&gt;Also generate our custom TIL and POSTS outputs&#xA;This is crucial for creating our multiple RSS feeds, as it instructs Hugo to actually generate these files when building the site.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;&lt;code&gt;[outputFormats]&lt;/code&gt;: This section allows you to define new output formats or modify existing ones. In our case, we&amp;rsquo;re defining two new output formats: TIL and POSTS. For each new format, we specify:&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;mediaType&lt;/code&gt;: This tells Hugo what kind of content this is. We&amp;rsquo;re using &amp;ldquo;application/rss+xml&amp;rdquo; because we&amp;rsquo;re creating RSS feeds.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;baseName&lt;/code&gt;: This determines the filename of the output file. For example, &lt;code&gt;baseName = &amp;quot;til&amp;quot;&lt;/code&gt; will result in a file named &lt;code&gt;til.xml&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;By defining these custom output formats, we&amp;rsquo;re giving Hugo the information it needs to generate our specialized RSS feeds.&lt;/p&gt;&#xA;&lt;p&gt;The interaction between these two configuration sections is key:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;[outputFormats]&lt;/code&gt; defines what the TIL and POSTS formats are&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;[outputs]&lt;/code&gt; tells Hugo to actually generate these formats for the home page&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This setup allows you to have fine-grained control over what files Hugo generates and how they&amp;rsquo;re named, which is exactly what we need to create multiple, specialized RSS feeds.&#xA;Is there any part of this you&amp;rsquo;d like me to elaborate on further?&#xA;&lt;/div&gt;&lt;/p&gt;&#xA;&lt;/details&gt;&#xA;&lt;p&gt;This helped but I still didn&amp;rsquo;t really get why I would have to add this to &lt;code&gt;home&lt;/code&gt; and not &lt;code&gt;page&lt;/code&gt; because I thought that I want to generate rss for page-types.&lt;/p&gt;&#xA;&lt;div class=&#34;promptbox&#34;&gt;&#xA;    &lt;div class=&#34;promptbox-title&#34;&gt;&#xA;        Prompt&#xA;    &lt;/div&gt;&#xA;    &lt;div class=&#34;promptbox-content&#34;&gt;&#xA;        What&amp;rsquo;s the difference between adding TIL and POSTS to home instead of page?      &lt;/div&gt; &#xA;&lt;/div&gt;&#xA;&lt;details class=&#34;llmbox llm-anthropic&#34;&gt;&#xA;    &lt;summary class=&#34;llmbox-title&#34;&gt;&#xA;        Model: claude-3-5-sonnet-20241022 - response &#xA;    &lt;/summary&gt;&#xA;    &lt;div class=&#34;llmbox-content&#34;&gt;&#xA;&lt;p&gt;That&amp;rsquo;s an excellent question! The difference between adding output formats to &lt;code&gt;home&lt;/code&gt; versus &lt;code&gt;page&lt;/code&gt; in Hugo&amp;rsquo;s configuration is quite significant and affects how and where these outputs are generated. Let me explain:&lt;/p&gt;&#xA;&lt;p&gt;Now, let me elaborate on the key points:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Scope and Purpose:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Adding TIL and POSTS to &lt;code&gt;home&lt;/code&gt; creates site-wide RSS feeds that include all relevant content from across your site. This is ideal for your use case of creating separate feeds for TIL entries and blog posts.&lt;/li&gt;&#xA;&lt;li&gt;If you added these to &lt;code&gt;page&lt;/code&gt;, it would create individual RSS feeds for each content page, which is not what you&amp;rsquo;re aiming for.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Number of Files Generated:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;With &lt;code&gt;home&lt;/code&gt;, you get one &lt;code&gt;til.xml&lt;/code&gt; and one &lt;code&gt;posts.xml&lt;/code&gt; file for your entire site.&lt;/li&gt;&#xA;&lt;li&gt;If you used &lt;code&gt;page&lt;/code&gt;, you&amp;rsquo;d get a &lt;code&gt;til.xml&lt;/code&gt; and &lt;code&gt;posts.xml&lt;/code&gt; for every single page on your site, which would be unnecessary and potentially confusing.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Content Aggregation:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The &lt;code&gt;home&lt;/code&gt; outputs can access and aggregate content from across your entire site, which is perfect for creating comprehensive RSS feeds.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;page&lt;/code&gt; outputs typically only contain information from that specific page.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Location of Generated Files:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;home&lt;/code&gt; outputs are usually placed at the root of your site, making them easy to find and link to (e.g., &lt;code&gt;https://yoursite.com/til.xml&lt;/code&gt;).&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;page&lt;/code&gt; outputs would be scattered throughout your site structure, mirroring your content organization.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Practical Implementation:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;For your RSS feeds, using &lt;code&gt;home&lt;/code&gt; allows you to create the three distinct feeds you want (TIL, posts, and everything) in a clean, organized manner.&lt;/li&gt;&#xA;&lt;li&gt;Using &lt;code&gt;page&lt;/code&gt; for this purpose would be impractical and wouldn&amp;rsquo;t achieve your goal of separate, comprehensive feeds.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;In summary, for your specific need of creating site-wide RSS feeds for different content types, adding TIL and POSTS to the &lt;code&gt;home&lt;/code&gt; outputs is the correct approach. It generates the feeds at the site level, includes all relevant content, and produces a single file for each feed type, which is exactly what you&amp;rsquo;re looking to achieve.&#xA;&lt;/div&gt;&lt;/p&gt;&#xA;&lt;/details&gt;&#xA;&lt;p&gt;I followed the suggested approach and added to my &lt;code&gt;config.toml&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# I want to top-level output html, rss, and my two custom outputs&lt;/span&gt;&#xA;&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;nx&#34;&gt;outputs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&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;home&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;html&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rss&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;til&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;post&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Here I define how to process these custom feeds&lt;/span&gt;&#xA;&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;nx&#34;&gt;outputFormats&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;til&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&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;mediaType&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;application/rss+xml&amp;#34;&lt;/span&gt;&#xA;&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;baseName&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;til&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&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;nx&#34;&gt;outputFormats&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;post&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&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;mediaType&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;application/rss+xml&amp;#34;&lt;/span&gt;&#xA;&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;baseName&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;posts&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then I built the page and hugo would build three different xml files:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;public/index.xml&#xA;public/posts.xml&#xA;public/til.xml&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, the files all had the same content as if they were built from the same template instead of the individual templates that filter by page type.&lt;/p&gt;&#xA;&lt;div class=&#34;promptbox&#34;&gt;&#xA;    &lt;div class=&#34;promptbox-title&#34;&gt;&#xA;        Prompt&#xA;    &lt;/div&gt;&#xA;    &lt;div class=&#34;promptbox-content&#34;&gt;&#xA;        This generates the three xml files but they all seem to use the same template file      &lt;/div&gt; &#xA;&lt;/div&gt;&#xA;&lt;details class=&#34;llmbox llm-anthropic&#34;&gt;&#xA;    &lt;summary class=&#34;llmbox-title&#34;&gt;&#xA;        Model: claude-3-5-sonnet-20241022 - response &#xA;    &lt;/summary&gt;&#xA;    &lt;div class=&#34;llmbox-content&#34;&gt;&#xA;&lt;p&gt;I apologize for the confusion in my previous explanation. You&amp;rsquo;re right to point out that issue. Let&amp;rsquo;s correct this and explain how to properly set up distinct templates for each RSS feed.&lt;/p&gt;&#xA;&lt;p&gt;Now, let me explain the key changes and why they solve the problem:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Template File Naming:&#xA;The crucial change is in how we name and place the template files. Instead of putting them in &lt;code&gt;layouts/_default/&lt;/code&gt;, we&amp;rsquo;re now creating:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;layouts/index.til.xml&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;layouts/index.posts.xml&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;layouts/index.xml&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This naming convention is important because Hugo uses it to match the output formats we defined in the configuration.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Template Content:&#xA;The content of each template remains largely the same, but we&amp;rsquo;ve made sure that each one is filtering for the correct content type:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;index.til.xml&lt;/code&gt; uses &lt;code&gt;{{ range where .Site.RegularPages &amp;quot;Type&amp;quot; &amp;quot;til&amp;quot; }}&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;index.posts.xml&lt;/code&gt; uses &lt;code&gt;{{ range where .Site.RegularPages &amp;quot;Type&amp;quot; &amp;quot;post&amp;quot; }}&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;index.xml&lt;/code&gt; continues to use &lt;code&gt;{{ range .Site.RegularPages }}&lt;/code&gt; for all content&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Configuration:&#xA;The configuration in &lt;code&gt;config.toml&lt;/code&gt; remains the same as before. The &lt;code&gt;[outputFormats]&lt;/code&gt; and &lt;code&gt;[outputs]&lt;/code&gt; sections are correctly set up to generate these files.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;How It Works:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;When Hugo sees &lt;code&gt;TIL&lt;/code&gt; in the &lt;code&gt;[outputs]&lt;/code&gt; section, it looks for a template named &lt;code&gt;index.til.xml&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Similarly, for &lt;code&gt;POSTS&lt;/code&gt;, it looks for &lt;code&gt;index.posts.xml&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;The default RSS output uses &lt;code&gt;index.xml&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;This setup ensures that each RSS feed uses its own template, allowing you to customize the content for each feed independently.&lt;/p&gt;&#xA;&lt;p&gt;The reason your previous attempt generated three XML files with the same content was likely because Hugo was falling back to a default RSS template when it couldn&amp;rsquo;t find specific templates for TIL and POSTS.&lt;/p&gt;&#xA;&lt;p&gt;With these changes, you should now have three distinct RSS feeds, each with its appropriate content. Does this explanation help clarify the issue? Would you like me to elaborate on any part of this solution?&#xA;&lt;/div&gt;&lt;/p&gt;&#xA;&lt;/details&gt;&#xA;&lt;p&gt;So I moved the template layout files as suggested to:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;layouts/index.til.xml&#xA;layouts/index.posts.xml&#xA;layouts/index.xml&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and they were correctly selected.&#xA;You can find the correct feeds here:&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;a href=&#34;https://staticnotes.org/index.xml&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;https://staticnotes.org/index.xml&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;a href=&#34;https://staticnotes.org/posts.xml&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;https://staticnotes.org/posts.xml&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;a href=&#34;https://staticnotes.org/til.xml&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;https://staticnotes.org/til.xml&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;&lt;/p&gt;&#xA; &lt;h2 id=&#34;conclusion&#34;&gt;&#xA;  &lt;a href=&#34;#conclusion&#34; class=&#34;header-link&#34;&gt;&#xA;    Conclusion&#xA;  &lt;/a&gt;&#xA;&lt;/h2&gt;&lt;p&gt;A common criticism is that LLMs will confidently hallucinate incorrect information. I think this will likely be true for the next couple of years. However, when I use the old-school google + stackoverflow + documentation + online discussion workflow I also might generate an incorrect approach. This can happen because I misunderstand the content or because I can&amp;rsquo;t piece the information from different sources correctly together for my use case.&lt;/p&gt;&#xA;&lt;p&gt;I think viewing an LLM as an interactive interface to search and combine information and context is the right mental model to use them productively.&lt;/p&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL about the QUALIFY statement in SQL</title>
      <link>/til/sql-qualify/</link>
      <pubDate>Mon, 16 Sep 2024 00:00:00 +0000</pubDate>
      
      <guid>/til/sql-qualify/</guid>
    <description>&lt;p&gt;Today I came across the &lt;code&gt;QUALIFY&lt;/code&gt; clause which is supported in some SQL dialects.&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt; It&amp;rsquo;s not part of the SQL standard but supported by main analytical databases like BigQuery, Snowflake, Oracle, Databricks, DuckDB, etc.&lt;/small&gt;&lt;/span&gt; It&amp;rsquo;s part of &#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Snowflake_Inc.&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;Snowflake&amp;rsquo;s&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;                style=&#34;height: 0.7em; width: 0.7em; margin-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;                class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;                viewBox=&#34;0 0 640 512&#34;&gt;&#xA;                &lt;path fill=&#34;currentColor&#34;&#xA;                    d=&#34;M640 51.2l-.3 12.2c-28.1 .8-45 15.8-55.8 40.3-25 57.8-103.3 240-155.3 358.6H415l-81.9-193.1c-32.5 63.6-68.3 130-99.2 193.1-.3 .3-15 0-15-.3C172 352.3 122.8 243.4 75.8 133.4 64.4 106.7 26.4 63.4 .2 63.7c0-3.1-.3-10-.3-14.2h161.9v13.9c-19.2 1.1-52.8 13.3-43.3 34.2 21.9 49.7 103.6 240.3 125.6 288.6 15-29.7 57.8-109.2 75.3-142.8-13.9-28.3-58.6-133.9-72.8-160-9.7-17.8-36.1-19.4-55.8-19.7V49.8l142.5 .3v13.1c-19.4 .6-38.1 7.8-29.4 26.1 18.9 40 30.6 68.1 48.1 104.7 5.6-10.8 34.7-69.4 48.1-100.8 8.9-20.6-3.9-28.6-38.6-29.4 .3-3.6 0-10.3 .3-13.6 44.4-.3 111.1-.3 123.1-.6v13.6c-22.5 .8-45.8 12.8-58.1 31.7l-59.2 122.8c6.4 16.1 63.3 142.8 69.2 156.7L559.2 91.8c-8.6-23.1-36.4-28.1-47.2-28.3V49.6l127.8 1.1 .2 .5z&#34;&gt;&#xA;                &lt;/path&gt;&#xA;            &lt;/svg&gt;&#xA;        &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; dialect which is the data warehouse that I use at work.&#xA;The &lt;code&gt;QUALIFY&lt;/code&gt; statement lets me filter the result of a query based on the result of a window function.&lt;/p&gt;&#xA;&lt;p&gt;The order of execution is the following:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-- SELECT &amp;lt;columns&amp;gt;&#xA;--   FROM &amp;lt;table&amp;gt;&#xA;--   [GROUP BY ...]&#xA;--   [HAVING ...]&#xA;--   QUALIFY &amp;lt;window function predicate&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;QUALIFY&lt;/code&gt; is for window functions what &lt;code&gt;HAVING&lt;/code&gt; is for group-by statements. It allows to filter based on the outputs of these operations without having to use a subquery or CTE. Therefore I can write more concise SQL.&lt;/p&gt;&#xA;&lt;p&gt;I often deduplicate data using the &lt;code&gt;row_number()&lt;/code&gt; window function. Sometimes I just want the latest event for a particular user in a dataset.&lt;/p&gt;&#xA;&lt;p&gt;An example would be:&lt;/p&gt;&#xA;&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;c1&#34;&gt;-- logs with some user events and timestamps&#xA;&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;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;logs_annotated&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&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;&#xA;&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;select&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;n&#34;&gt;logs&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;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;n&#34;&gt;row_number&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;n&#34;&gt;over&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;n&#34;&gt;partition&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;by&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_id&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;order&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;by&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event_timestamp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;desc&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;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;row_number&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;logs&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;&#xA;&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;select&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;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;logs_annotated&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;where&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;row_number&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;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With &lt;code&gt;QUALIFY&lt;/code&gt; I can write one statement instead:&lt;/p&gt;&#xA;&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;k&#34;&gt;select&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;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;logs&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;n&#34;&gt;qualify&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;row_number&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;n&#34;&gt;over&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;n&#34;&gt;partition&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;by&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_id&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;order&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;by&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event_timestamp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;desc&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;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works because the &lt;code&gt;QUALIFY&lt;/code&gt; statement is evaluated after the window function result has been computed and can therefore be used in filtering.&lt;/p&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL about just and justfiles</title>
      <link>/til/just-command-runner/</link>
      <pubDate>Fri, 13 Sep 2024 00:00:00 +0000</pubDate>
      
      <guid>/til/just-command-runner/</guid>
    <description>&lt;p&gt;&#xA;&lt;a href=&#34;https://github.com/casey/just&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;just&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; is &lt;em&gt;just&lt;/em&gt; a command runner that I recently started using to define aliases for commands in my projects, e.g. build, test, or deploy commands.&lt;/p&gt;&#xA; &lt;h3 id=&#34;installation&#34;&gt;&#xA;  &lt;a href=&#34;#installation&#34; class=&#34;header-link&#34;&gt;&#xA;    Installation&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;just&lt;/code&gt; can be installed via homebrew:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;brew install just&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;h3 id=&#34;example&#34;&gt;&#xA;  &lt;a href=&#34;#example&#34; class=&#34;header-link&#34;&gt;&#xA;    Example&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;I want to create alias commands for my &#xA;&lt;a href=&#34;https://www.getdbt.com/&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;dbt&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; project to build my dbt models in production vs. development environments. At the moment, I need to run the commands:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# prod warehouse&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;poetry run dbt run --target prod&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# dev warehouse&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;poetry run dbt run --target dev&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To define shorter just commands for this project I add a &lt;code&gt;justfile&lt;/code&gt; into the project folder.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# justfile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;run-prod *ARGS:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    poetry run dbt run --target prod {{ARGS}}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;run-dev *ARGS:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    poetry run dbt run --target dev {{ARGS}}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If I am inside the project folder I can now run &lt;code&gt;just run-prod&lt;/code&gt; and &lt;code&gt;just run-dev&lt;/code&gt;. Moreover, I can pass in any dbt keyword arguments, e.g.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;just run-dev --select mymodel&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;will resolve to&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;poetry run dbt run --target dev --select mymodel&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;h3 id=&#34;is-this-not-just-make&#34;&gt;&#xA;  &lt;a href=&#34;#is-this-not-just-make&#34; class=&#34;header-link&#34;&gt;&#xA;    Is this not just &lt;code&gt;make&lt;/code&gt;?&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;just&lt;/code&gt; is inspired by the Unix build tool &#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Make_%28software%29&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;make&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;                style=&#34;height: 0.7em; width: 0.7em; margin-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;                class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;                viewBox=&#34;0 0 640 512&#34;&gt;&#xA;                &lt;path fill=&#34;currentColor&#34;&#xA;                    d=&#34;M640 51.2l-.3 12.2c-28.1 .8-45 15.8-55.8 40.3-25 57.8-103.3 240-155.3 358.6H415l-81.9-193.1c-32.5 63.6-68.3 130-99.2 193.1-.3 .3-15 0-15-.3C172 352.3 122.8 243.4 75.8 133.4 64.4 106.7 26.4 63.4 .2 63.7c0-3.1-.3-10-.3-14.2h161.9v13.9c-19.2 1.1-52.8 13.3-43.3 34.2 21.9 49.7 103.6 240.3 125.6 288.6 15-29.7 57.8-109.2 75.3-142.8-13.9-28.3-58.6-133.9-72.8-160-9.7-17.8-36.1-19.4-55.8-19.7V49.8l142.5 .3v13.1c-19.4 .6-38.1 7.8-29.4 26.1 18.9 40 30.6 68.1 48.1 104.7 5.6-10.8 34.7-69.4 48.1-100.8 8.9-20.6-3.9-28.6-38.6-29.4 .3-3.6 0-10.3 .3-13.6 44.4-.3 111.1-.3 123.1-.6v13.6c-22.5 .8-45.8 12.8-58.1 31.7l-59.2 122.8c6.4 16.1 63.3 142.8 69.2 156.7L559.2 91.8c-8.6-23.1-36.4-28.1-47.2-28.3V49.6l127.8 1.1 .2 .5z&#34;&gt;&#xA;                &lt;/path&gt;&#xA;            &lt;/svg&gt;&#xA;        &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; from 1978. However, &lt;code&gt;just&lt;/code&gt; is not a build system and focuses solely on command running. This avoids having to deal with things like &lt;code&gt;.PHONY&lt;/code&gt; that can can catch you out in &lt;code&gt;make&lt;/code&gt; recipes. I also like two additional features of &lt;code&gt;just&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I can run my &lt;code&gt;just&lt;/code&gt; commands from any subfolder of the project folder that contains the &lt;code&gt;justfile&lt;/code&gt;. This is useful when I work on this blog. I have to run &lt;code&gt;hugo serve&lt;/code&gt; from the top-level project folder and jupyter-to-markdown converter &lt;code&gt;nb2hugo&lt;/code&gt; from the &lt;code&gt;notebooks/project_x/&lt;/code&gt; subfolder. With &lt;code&gt;just&lt;/code&gt; command aliases it doesn&amp;rsquo;t matter from which folder I run the command.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;just&lt;/code&gt; allows you to load environmental variables from an &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;&#xA;&lt;p&gt;Example &lt;code&gt;.env&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;DATABASE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;localhost:1111&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;USERACCOUNT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;rob1234&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add &lt;code&gt;set load-dotenv&lt;/code&gt; to your &lt;code&gt;justfile&lt;/code&gt; and the environment variables will be available in your shell:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; dotenv-load&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;check-vars:&#xA;&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;s2&#34;&gt;&amp;#34;Env vars are DATABASE:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DATABASE&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; and USER:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$USERACCOUNT&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;                                                                &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running &lt;code&gt;just check-vars&lt;/code&gt; will output:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Env vars are DATABASE:localhost:1111 and USER:rob1234&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL to create continuously numbered lists with content between items</title>
      <link>/til/markdown-lists/</link>
      <pubDate>Wed, 21 Aug 2024 00:00:00 +0000</pubDate>
      
      <guid>/til/markdown-lists/</guid>
    <description>&lt;p&gt;When writing notes in markdown I commonly encounter the problem that I want to create an automatically numbered list with content between the items. However, this messes up the numbering as it creates two separate numbered lists, e.g.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;My first point&lt;/li&gt;&#xA;&lt;li&gt;My second point&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;code&gt;code block or image&lt;/code&gt;&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;My third point&lt;/li&gt;&#xA;&lt;li&gt;My fourth point&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;The solution to this is &lt;em&gt;embarrassingly obvious&lt;/em&gt; once you know it. Just move the image or code block one level down by indenting it with four spaces. This keeps the list intact.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;My first point&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;My second point&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;code block or image&lt;/code&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;My third point&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;My fourth point&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL how to set a lower threshold on a column in SQL</title>
      <link>/til/greatest-sql/</link>
      <pubDate>Wed, 07 Aug 2024 00:00:00 +0000</pubDate>
      
      <guid>/til/greatest-sql/</guid>
    <description>&lt;p&gt;For the last couple of months I came across multiple instances where I wanted to write an SQL query to lower threshold all the values in a particular column in one of our Snowflake tables.&lt;/p&gt;&#xA;&lt;p&gt;I used quite clunky workarounds to do that. It turns out you can use the SQL functions &lt;code&gt;GREATEST&lt;/code&gt; or &lt;code&gt;LEAST&lt;/code&gt; for it.&lt;/p&gt;&#xA; &lt;h3 id=&#34;example&#34;&gt;&#xA;  &lt;a href=&#34;#example&#34; class=&#34;header-link&#34;&gt;&#xA;    Example&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;I am creating a temporary table in the first CTE with a column &lt;code&gt;DATA_COLUMN&lt;/code&gt; that has positive and negative numbers.&lt;/p&gt;&#xA;&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;k&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;example_table&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&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;&#xA;&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;SELECT&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; &#xA;&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;FROM&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;&#xA;&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;VALUES&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;mi&#34;&gt;1&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;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;423&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;mi&#34;&gt;2&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;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;mi&#34;&gt;3&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;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;001&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;mi&#34;&gt;4&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;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;mi&#34;&gt;5&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;12&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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 class=&#34;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t&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;n&#34;&gt;row_nr&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;n&#34;&gt;data_column&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;&#xA;&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;&#xA;&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;select&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GREATEST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DATA_COLUMN&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;0&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;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;thresholded&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;example_table&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Output:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;0.000&#xA;5.000&#xA;0.000&#xA;100.000&#xA;12.000&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The function&amp;rsquo;s primary purpose is to take the greatest value among a number of referenced columns, e.g. &lt;code&gt;GREATEST(column1, column2, column3)&lt;/code&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL how to set up a local LLM as an assistant in VSCode</title>
      <link>/til/using-local-llms/</link>
      <pubDate>Wed, 10 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>/til/using-local-llms/</guid>
    <description>&lt;p&gt;I am still trying to get used to the fact that the product of state-of-the-art AI companies is essentially a GB-sized CSV file and some instructions about the network architecture to perform the inference. Recently released &amp;ldquo;open source&amp;rdquo; models of medium-size are showing quite decent performance on &#xA;&lt;a href=&#34;https://artificialanalysis.ai/&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;benchmarks&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;, so I was interested how easy it would be to set them up locally to help me with coding tasks in VSCode. Short answer: very easy.&lt;/p&gt;&#xA;&lt;p&gt;The bad news first. Those local small-to-medium sized models won&amp;rsquo;t reach the performance of remotely hosted GPT models. I also think the local inference will likely influence battery life of your machine, but there are also some benefits of local LLMs:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;free, local inference from &amp;ldquo;open-source&amp;rdquo; models (no company lock-in for inference)&lt;/li&gt;&#xA;&lt;li&gt;works without internet access which can also substitute a quick google search if one is in a place with bad reception&lt;/li&gt;&#xA;&lt;li&gt;no sharing of sensitive information with 3rd parties&lt;/li&gt;&#xA;&lt;li&gt;customizability. You can pick a model fine-tuned for your use specific use-case&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&#xA;&#xA;&lt;figure&gt;&#xA;  &lt;div class=&#34;image-wrapper&#34;&gt;&#xA;  &lt;img src=&#34;llm_on_plane.jpg&#34; alt=&#34;Running local LLM on plane&#34; loading=&#34;lazy&#34; /&gt;&#xA;  &lt;figcaption&gt;Figure 1. Using codellama for work on a low-cost carrier flight without internet access.&lt;/figcaption&gt;&#xA;  &lt;/div&gt;&#xA;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA; &lt;h3 id=&#34;hardware-requirements&#34;&gt;&#xA;  &lt;a href=&#34;#hardware-requirements&#34; class=&#34;header-link&#34;&gt;&#xA;    Hardware requirements&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;I am using a 2018 MacBook Pro with MacOS and VSCode. For 7B parameter models you need 8GB+ of RAM, for 13B parameter models you need 16GB+ of RAM. Smaller models also return the response quicker. So far a 7B parameter model gives me a response within 3-5s.&lt;/p&gt;&#xA; &lt;h3 id=&#34;downloading-local-models&#34;&gt;&#xA;  &lt;a href=&#34;#downloading-local-models&#34; class=&#34;header-link&#34;&gt;&#xA;    Downloading local models&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;To manage models and handle the inference interface, we use &#xA;&lt;a href=&#34;https://ollama.ai/blog/run-code-llama-locally&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;Ollama&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; as our model provider:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-cli&#34; data-lang=&#34;cli&#34;&gt;brew install ollama&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then, we use the &lt;code&gt;ollama pull [model_name]&lt;/code&gt; command to download one of the models from Ollama&amp;rsquo;s model &#xA;&lt;a href=&#34;https://ollama.ai/library&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;library&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;. I am using Meta’s open source&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt; Unfortunately, in 2023 open source in the context of LLMs for most people with small budgets means: open to use, not open to reproduce.&lt;/small&gt;&lt;/span&gt;Llama2 model fine-tuned for coding tasks and a “moderate size” of 7b parameters. &lt;strong&gt;To get the familiar chat-like experience, use an instruct model&lt;/strong&gt; that was trained to output human-like answers to questions. More details about the different model variations and the intended use cases can be found &#xA;&lt;a href=&#34;https://ollama.ai/blog/how-to-prompt-code-llama&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;here&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;In the CLI run: &lt;code&gt;ollama pull codellama:7b-instruct&lt;/code&gt; This will download the 3.8GB model from the internet and save the model parameters to your hard drive.&lt;/p&gt;&#xA; &lt;h3 id=&#34;prompting-the-model-from-cli&#34;&gt;&#xA;  &lt;a href=&#34;#prompting-the-model-from-cli&#34; class=&#34;header-link&#34;&gt;&#xA;    Prompting the model from CLI&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;After downloading the model, we can prompt it from the CLI with&#xA;&lt;code&gt;ollama run codellama:7b-instruct&lt;/code&gt; and then type in our prompt.&lt;/p&gt;&#xA; &lt;h3 id=&#34;using-the-model-as-a-coding-assistant-inside-vs-code&#34;&gt;&#xA;  &lt;a href=&#34;#using-the-model-as-a-coding-assistant-inside-vs-code&#34; class=&#34;header-link&#34;&gt;&#xA;    Using the model as a coding assistant inside VS Code&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;To prompt the model from within VSCode I am using the extension &lt;code&gt;Continue&lt;/code&gt;. By default &lt;code&gt;Continue&lt;/code&gt; uses GPT-4 in trial mode. However, you can point &lt;code&gt;Continue&lt;/code&gt; to any local or remote model by specifying local paths, API keys, etc. in the &lt;code&gt;config.json&lt;/code&gt;. In our case we want to point &lt;code&gt;Continue&lt;/code&gt; to our codellama model, so we add the following to the file:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// config.json&#xA;&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;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;models&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&#xA;&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;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;GPT-4&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;provider&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;openai-free-trial&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;model&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;gpt-4&amp;#34;&lt;/span&gt;&#xA;&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;&#xA;&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;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;GPT-3.5-Turbo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;provider&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;openai-free-trial&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;model&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;gpt-3.5-turbo&amp;#34;&lt;/span&gt;&#xA;&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;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// add the local model here&#xA;&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;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;codellama:7b-instruct&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;model&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;codellama:7b-instruct&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;contextLength&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4096&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;provider&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ollama&amp;#34;&lt;/span&gt;&#xA;&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;&#xA;&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;err&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The nice thing about &lt;code&gt;Continue&lt;/code&gt; is that it allows you to easily jump between local and remote models. This is useful if you are unhappy with a response and want to try a different model.&lt;/p&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL how to generate a dbt staging model description from snowflake table</title>
      <link>/til/generate-dbt-staging-model/</link>
      <pubDate>Wed, 04 Oct 2023 00:00:00 +0000</pubDate>
      
      <guid>/til/generate-dbt-staging-model/</guid>
    <description>&lt;p&gt;In my team we use &#xA;&lt;a href=&#34;https://www.getdbt.com/product/what-is-dbt&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;dbt&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; to create, document, and test data models in our data warehouse, &#xA;&lt;a href=&#34;https://www.snowflake.com/en/&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;snowflake&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt;. We use different layers of models that start from the raw data and in each layer increase complexity and specialization for the target use case:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;source data in a raw table&lt;/li&gt;&#xA;&lt;li&gt;thin staging models (standardization of columns, no joins, no aggregations)&lt;/li&gt;&#xA;&lt;li&gt;intermediate models (reoccurring building blocks that are defined once and used across models in the next layer)&lt;/li&gt;&#xA;&lt;li&gt;mart models (most detailed models organised by department / business context / application)&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA; &lt;h3 id=&#34;problem&#34;&gt;&#xA;  &lt;a href=&#34;#problem&#34; class=&#34;header-link&#34;&gt;&#xA;    Problem&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;The creation of staging models can sometimes be a bit mind-numbing, especially when the raw table has many columns. Let&amp;rsquo;s take a small example table &lt;code&gt;USERS&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;id&lt;/th&gt;&#xA;          &lt;th&gt;first_name&lt;/th&gt;&#xA;          &lt;th&gt;last_name&lt;/th&gt;&#xA;          &lt;th&gt;country&lt;/th&gt;&#xA;          &lt;th&gt;is_active&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;1&lt;/td&gt;&#xA;          &lt;td&gt;Peter&lt;/td&gt;&#xA;          &lt;td&gt;Clark&lt;/td&gt;&#xA;          &lt;td&gt;US&lt;/td&gt;&#xA;          &lt;td&gt;True&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;2&lt;/td&gt;&#xA;          &lt;td&gt;Sarah&lt;/td&gt;&#xA;          &lt;td&gt;Svenson&lt;/td&gt;&#xA;          &lt;td&gt;Sweden&lt;/td&gt;&#xA;          &lt;td&gt;False&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;3&lt;/td&gt;&#xA;          &lt;td&gt;Roberto&lt;/td&gt;&#xA;          &lt;td&gt;Gonzales&lt;/td&gt;&#xA;          &lt;td&gt;Spain&lt;/td&gt;&#xA;          &lt;td&gt;True&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;and dbt staging model &lt;code&gt;stg_users.sql&lt;/code&gt;:&lt;/p&gt;&#xA;&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;k&#34;&gt;select&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;n&#34;&gt;first_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;varchar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;first_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;n&#34;&gt;last_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;varchar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;last_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;n&#34;&gt;country&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;varchar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;country&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;n&#34;&gt;is_active&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;boolean&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_active&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;source&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;RAW_DATA&amp;#39;&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;s1&#34;&gt;&amp;#39;USERS&amp;#39;&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;err&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The staging model definition typically follows the pattern: &lt;code&gt;raw-table-column-name::type as staging-model-column-name&lt;/code&gt;. I have used vim macros in the past to quickly write the staging model definition, but often end up copy-pasting and looking up the inferred types in snowflake for ten minutes.&lt;/p&gt;&#xA; &lt;h3 id=&#34;solution&#34;&gt;&#xA;  &lt;a href=&#34;#solution&#34; class=&#34;header-link&#34;&gt;&#xA;    Solution&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;We can run two SQL queries in snowflake to generate most of the dbt model defintion:&lt;/p&gt;&#xA;&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;k&#34;&gt;desc&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;RAW_DATA&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;DATA_SCHEMA&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;USERS&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;select&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CONCAT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;name&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;s1&#34;&gt;&amp;#39;::&amp;#39;&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;s2&#34;&gt;&amp;#34;type&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;s1&#34;&gt;&amp;#39; as &amp;#39;&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;s2&#34;&gt;&amp;#34;name&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;s1&#34;&gt;&amp;#39;,&amp;#39;&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;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dbt_model_def&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result_scan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;LAST_QUERY_ID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first line (&lt;code&gt;DESCRIBE TABLE&lt;/code&gt;) outputs the table definition. The second command takes the column name and type information about the table and concatenates them into the right format:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;LAST_QUERY_ID()&lt;/code&gt;: returns the id of the desc table query&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;RESULT_SCAN()&lt;/code&gt;: returns the result of the last command&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;TABLE()&lt;/code&gt;: converts the output to a queryable table&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The output of the query is a table with each row formatted with the above pattern. We can copy-paste the output in one step into our staging model file.&lt;/p&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL how to use snowflake&#39;s VALUES sub-clause</title>
      <link>/til/sql-values-subclause/</link>
      <pubDate>Tue, 03 Oct 2023 00:00:00 +0000</pubDate>
      
      <guid>/til/sql-values-subclause/</guid>
    <description>&lt;p&gt;Today I found out about the useful &#xA;&lt;a href=&#34;https://docs.snowflake.com/en/sql-reference/constructs/values&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;VALUES()&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; sub-clause in snowflake that allows you to dynamically generate a fixed, known set of rows inside your query.&lt;/p&gt;&#xA; &lt;h3 id=&#34;problem&#34;&gt;&#xA;  &lt;a href=&#34;#problem&#34; class=&#34;header-link&#34;&gt;&#xA;    Problem&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;I had a table &lt;code&gt;exchange_rates&lt;/code&gt; of EUR-currency pairs with their corresponding exchange rates&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;date&lt;/th&gt;&#xA;          &lt;th&gt;base_currency&lt;/th&gt;&#xA;          &lt;th&gt;target_currency&lt;/th&gt;&#xA;          &lt;th&gt;exchange_rate&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;2023-10-03&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;EUR&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;GBP&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;0.87&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;2023-10-03&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;EUR&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;USD&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;1.05&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;2023-10-03&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;EUR&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;JPY&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;155.95&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;that I wanted to join with a table &lt;code&gt;transactions&lt;/code&gt; which contained transaction prices in different currencies:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;id&lt;/th&gt;&#xA;          &lt;th&gt;price&lt;/th&gt;&#xA;          &lt;th&gt;price_currency&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;1&lt;/td&gt;&#xA;          &lt;td&gt;100.53&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;GBP&amp;rsquo;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;2&lt;/td&gt;&#xA;          &lt;td&gt;1021.68&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;EUR&amp;rsquo;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;3&lt;/td&gt;&#xA;          &lt;td&gt;7.99&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;JPY&amp;rsquo;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;My goal was to standardize all prices to EUR.&lt;/p&gt;&#xA;&lt;p&gt;The SQL query to join the two tables would be:&lt;/p&gt;&#xA;&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;k&#34;&gt;select&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;n&#34;&gt;price&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;n&#34;&gt;price_currency&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;n&#34;&gt;exchange_rate&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;transactions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;inner&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;exchange_rates&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;er&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;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;er&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;target_currency&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;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;price_currency&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The issue was that &lt;code&gt;exchange_rates&lt;/code&gt; did not have a &lt;code&gt;EUR&lt;/code&gt;-&lt;code&gt;EUR&lt;/code&gt; currency pair and I didn&amp;rsquo;t have access to the data source. So, the inner join would filter out all EUR transactions (or leave NULLs in case of a left join).&#xA;&lt;span class=&#34;sidenote-number&#34;&gt;&lt;small class=&#34;sidenote&#34;&gt;This is a bit of a constructed problem to show an application of VALUES(). One could alternatively fill the NULLs with 1.0s after a left join.&lt;/small&gt;&lt;/span&gt;&lt;/p&gt;&#xA; &lt;h3 id=&#34;solution&#34;&gt;&#xA;  &lt;a href=&#34;#solution&#34; class=&#34;header-link&#34;&gt;&#xA;    Solution&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;I used snowflake&amp;rsquo;s &lt;code&gt;VALUES()&lt;/code&gt; to dynamically generate another row in the query. I use this with a &lt;code&gt;UNION&lt;/code&gt; statement to complete the exchange_rates table before joining:&lt;/p&gt;&#xA;&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;k&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;exchange_rates_complete&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&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;&#xA;&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;select&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;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;exchange_rates&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;union&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;select&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;from&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;k&#34;&gt;values&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;s1&#34;&gt;&amp;#39;2023-10-03&amp;#39;&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;s1&#34;&gt;&amp;#39;EUR&amp;#39;&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;s1&#34;&gt;&amp;#39;EUR&amp;#39;&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;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&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;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;&#xA;&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;&#xA;&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;select&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &#xA;&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;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;n&#34;&gt;price&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;n&#34;&gt;price_currency&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;n&#34;&gt;exchange_rate&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;from&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;transactions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&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;inner&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;exchange_rates_complete&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;er&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;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;er&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;target_currency&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;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;price_currency&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The joined table looks like this:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;id&lt;/th&gt;&#xA;          &lt;th&gt;price&lt;/th&gt;&#xA;          &lt;th&gt;price_currency&lt;/th&gt;&#xA;          &lt;th&gt;exchange_rate&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;1&lt;/td&gt;&#xA;          &lt;td&gt;100.53&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;GBP&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;0.87&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;2&lt;/td&gt;&#xA;          &lt;td&gt;1021.68&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;EUR&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;1.0&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;3&lt;/td&gt;&#xA;          &lt;td&gt;7.99&lt;/td&gt;&#xA;          &lt;td&gt;&amp;lsquo;JPY&amp;rsquo;&lt;/td&gt;&#xA;          &lt;td&gt;155.95&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;</description>
    </item>
    
    
    <item>
      <title>TIL how to debug a broken nextcloud login</title>
      <link>/til/nextcloud-login-debugging/</link>
      <pubDate>Sat, 19 Aug 2023 00:00:00 +0000</pubDate>
      
      <guid>/til/nextcloud-login-debugging/</guid>
    <description>&lt;p&gt;For the past month I was confronted with the downside of self-hosting. I use Nextcloud for me and my partner&amp;rsquo;s calendar, online file storage, and notes syncing. I host Nextcloud on a small 7EUR/month Hetzner VPC. Unfortunately, about a month ago it stopped working. Phone apps would not sync the calendar, Joplin notes were not synced across devices and I could not log into my Nextcloud account. I avoided trying to fix the issue quickly, because I know from experience that a short bug investigation in a self-hosting project can quickly spiral into a weekend long endeavour. Fortunately, I had some time this morning and I could fix the issue quickly. Leaving this here for future reference.&lt;/p&gt;&#xA; &lt;h3 id=&#34;problem&#34;&gt;&#xA;  &lt;a href=&#34;#problem&#34; class=&#34;header-link&#34;&gt;&#xA;    Problem&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;Phone and Mac apps stopped syncing data with the Nextcloud instance. In my browser I could access the login page, but after entering the details I was being sent back to the same login page that you see below without any error message.&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&lt;figure&gt;&#xA;  &lt;div class=&#34;image-wrapper&#34;&gt;&#xA;  &lt;img src=&#34;nextcloud_login.jpg&#34; alt=&#34;Nextcloud login window&#34; loading=&#34;lazy&#34; /&gt;&#xA;  &lt;figcaption&gt;Figure 1. Login window in my browser that I was being redirected to.&lt;/figcaption&gt;&#xA;  &lt;/div&gt;&#xA;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA; &lt;h3 id=&#34;investigation&#34;&gt;&#xA;  &lt;a href=&#34;#investigation&#34; class=&#34;header-link&#34;&gt;&#xA;    Investigation&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;It is quite difficult to understand the issue without an error message. The Nextcloud docs suggest to look at the server logs to get a better idea.&lt;/p&gt;&#xA;&lt;p&gt;To access the logs I use ssh to log into the VPC and opened the &lt;code&gt;nextcloud.log&lt;/code&gt; log file.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ ssh username@[VPC-IP] &#xA;$ vim /var/www/nextcloud/data/nextcloud.log&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Trying to open the file in vim showed me the likely issue. The log file was so large that it would take minutes to open. From the error message I could see that nextcloud ran out of space during previous requests.&lt;/p&gt;&#xA; &lt;h3 id=&#34;solution&#34;&gt;&#xA;  &lt;a href=&#34;#solution&#34; class=&#34;header-link&#34;&gt;&#xA;    Solution&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&lt;p&gt;Truncate the big log file using the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Put nextcloud in maintenance mode.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Set &lt;code&gt;&#39;maintenance&#39; =&amp;gt; true&lt;/code&gt; in the config file &lt;code&gt;/var/www/nextcloud/config/config.php&lt;/code&gt;&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# config.php&#xA;&amp;lt;?php&#xA;[...]&#xA;  &amp;#39;dbtype&amp;#39; =&amp;gt; &amp;#39;mysql&amp;#39;,&#xA;  &amp;#39;version&amp;#39; =&amp;gt; &amp;#39;22.2.3.0&amp;#39;,&#xA;  &amp;#39;dbname&amp;#39; =&amp;gt; &amp;#39;nextcloud&amp;#39;,&#xA;  &amp;#39;dbhost&amp;#39; =&amp;gt; &amp;#39;localhost&amp;#39;,&#xA;  &amp;#39;dbport&amp;#39; =&amp;gt; &amp;#39;&amp;#39;,&#xA;  &amp;#39;dbtableprefix&amp;#39; =&amp;gt; &amp;#39;oc_&amp;#39;,&#xA;  &amp;#39;installed&amp;#39; =&amp;gt; true,&#xA;  &amp;#39;maintenance&amp;#39; =&amp;gt; true,&#xA;  &amp;#39;theme&amp;#39; =&amp;gt; &amp;#39;&amp;#39;,&#xA;  &amp;#39;loglevel&amp;#39; =&amp;gt; 0,&#xA;[...]&#xA;);&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;Looking at the config file, I also noticed that I had &lt;code&gt;loglevel&lt;/code&gt; set to 0 (the most verbose), which is the likely cause of the file size. Nextcloud has the following log levels:&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;0: DEBUG: All activity; the most detailed logging.&lt;/li&gt;&#xA;&lt;li&gt;1: INFO: Activity such as user logins and file activities, plus warnings, errors, and fatal errors.&lt;/li&gt;&#xA;&lt;li&gt;2: WARN: Operations succeed, but with warnings of potential problems, plus errors and fatal errors.&lt;/li&gt;&#xA;&lt;li&gt;3: ERROR: An operation fails, but other services and operations continue, plus fatal errors.&lt;/li&gt;&#xA;&lt;li&gt;4: FATAL: The server stops.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;So I changed &lt;code&gt;&#39;loglevel&#39; =&amp;gt; 2&lt;/code&gt; to prevent the same issue from reappearing in a year.&lt;/p&gt;&#xA;&lt;ol start=&#34;3&#34;&gt;&#xA;&lt;li&gt;Truncate the log file to 0 bytes to free space using the unix &#xA;&lt;a href=&#34;https://man7.org/linux/man-pages/man1/truncate.1.html&#34; &#xA;&#xA;    target=&#34;_blank&#34;&#xA;    &gt;truncate&#xA;    &#xA;        &lt;span style=&#34;white-space: nowrap&#34;&gt;&amp;thinsp;&lt;svg&#xA;            style=&#34;height: 0.7em; width: 0.7em; padding-left: -0.2em;&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;external-link-alt&#34;&#xA;            class=&#34;svg-inline--fa fa-external-link-alt fa-w-16&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&#xA;            viewBox=&#34;0 0 512 512&#34;&gt;&#xA;            &lt;path fill=&#34;currentColor&#34;&#xA;                d=&#34;M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z&#34;&gt;&#xA;            &lt;/path&gt;&#xA;        &lt;/svg&gt;&#xA;    &lt;/span&gt;&#xA;        &#xA;    &#xA;&lt;/a&gt; command:&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$sudo -u www-data truncate /var/www/nextcloud/data/nextcloud.log --size 0&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=&#34;4&#34;&gt;&#xA;&lt;li&gt;Disable maintenance mode &lt;code&gt;&#39;maintenance&#39; =&amp;gt; false&lt;/code&gt; in the config file.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;This allowed me to login using my browser. Moreover, all apps started syncing again.&lt;/p&gt;&#xA;</description>
    </item>
    
  </channel>
</rss>