<?xml version='1.0' encoding='utf-8'?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>rand[om]</title><link href="https://ricardoanderegg.com/" /><link rel="self" type="application/atom+xml" href="https://ricardoanderegg.com/atom.xml" /><id>https://ricardoanderegg.com/</id><updated>2026-01-27T00:00:00+00:00</updated><author><name>Ricardo Ander-Egg</name></author><entry><title>Two-step structured outputs for LLMs</title><link href="https://ricardoanderegg.com/posts/two-step-structured-outputs-llm/" /><id>https://ricardoanderegg.com/posts/two-step-structured-outputs-llm/</id><published>2026-01-27T00:00:00+00:00</published><updated>2026-01-27T00:00:00+00:00</updated><content type="html">&lt;p&gt;I&amp;rsquo;m experimenting with a two-step pipeline for structured outputs. Instead of asking for JSON in a single prompt, I capture the raw free-text response first, then format it in a second call.&lt;/p&gt;
&lt;h2 id="why-bother"&gt;Why bother?&lt;/h2&gt;
&lt;p&gt;Schema validation errors don&amp;rsquo;t invalidate the LLM response. If the JSON is malformed, I only retry the formatting step. The original reasoning is still there.&lt;/p&gt;
&lt;p&gt;Most errors I see in data extraction pipelines are the model messing up JSON tokens, not the response being wrong. A missing bracket shouldn&amp;rsquo;t waste a complex reasoning chain.&lt;/p&gt;</content></entry><entry><title>Software Willy Wonka</title><link href="https://ricardoanderegg.com/posts/if-llms-replace-programmers-be-willy-wonka/" /><id>https://ricardoanderegg.com/posts/if-llms-replace-programmers-be-willy-wonka/</id><published>2026-01-19T00:00:00+00:00</published><updated>2026-01-19T00:00:00+00:00</updated><content type="html">&lt;p&gt;I call my LLM agents &amp;ldquo;Oompa-Loompas&amp;rdquo;. It started as a fun way to refer to them, especially when talking to non-technical people. They normally just know &amp;ldquo;ChatGPT&amp;rdquo;, but I use Claude Code, Codex, and a bunch of others. At some point it felt weird to keep saying &amp;ldquo;ChatGPT&amp;rdquo; when that&amp;rsquo;s not even what I&amp;rsquo;m using. So I needed a term that covered all of them. Oompa-Loompas.&lt;/p&gt;
&lt;p&gt;Now I realize the metaphor goes deeper than I thought.&lt;/p&gt;</content></entry><entry><title>Fixing Claude Code's broken file search</title><link href="https://ricardoanderegg.com/posts/claude-code-file-suggestion-hook/" /><id>https://ricardoanderegg.com/posts/claude-code-file-suggestion-hook/</id><published>2026-01-14T00:00:00+00:00</published><updated>2026-01-14T00:00:00+00:00</updated><content type="html">&lt;p&gt;Claude Code has a nice feature where you can type &lt;code&gt;@&lt;/code&gt; followed by a file name to reference files in your conversation. The problem is that it&amp;rsquo;s broken. At least for me, it doesn&amp;rsquo;t work well when the &lt;code&gt;.git&lt;/code&gt; folder is not in the repo root; like when using git worktrees. There&amp;rsquo;s &lt;a href="https://github.com/anthropics/claude-code/issues/14399"&gt;an open issue&lt;/a&gt; about it.&lt;/p&gt;
&lt;p&gt;After some frustration, I decided to write my own file suggestion hook.&lt;/p&gt;
&lt;h2 id="the-hook-system"&gt;The Hook System&lt;/h2&gt;
&lt;p&gt;Claude Code lets you override the file suggestion behavior with a custom command. You configure it in your settings file (&lt;code&gt;.claude/settings.json&lt;/code&gt;):&lt;/p&gt;</content></entry><entry><title>Getting better at coding with LLMs</title><link href="https://ricardoanderegg.com/posts/getting-better-coding-llms-agents/" /><id>https://ricardoanderegg.com/posts/getting-better-coding-llms-agents/</id><published>2026-01-11T00:00:00+00:00</published><updated>2026-01-11T00:00:00+00:00</updated><content type="html">&lt;p&gt;In LLM coding, people will spend weeks learning frameworks and tooling, and spend basically zero time learning how to talk to the thing that&amp;rsquo;s actually writing the code.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m pretty sure I&amp;rsquo;m the #1 power user of coding AI tools at my company (Claude Code, Codex, etc). People asked me to showcase how I use them. As I&amp;rsquo;m planning it, I notice the main idea I want to share is: using these tools is a skill. Like sports. You don&amp;rsquo;t get good by copying someone else&amp;rsquo;s &amp;ldquo;perfect routine&amp;rdquo;.&lt;/p&gt;</content></entry><entry><title>Preact without a build step, including routing and signals</title><link href="https://ricardoanderegg.com/posts/preact-without-build-step-including-routing/" /><id>https://ricardoanderegg.com/posts/preact-without-build-step-including-routing/</id><published>2025-12-21T00:00:00+00:00</published><updated>2025-12-21T00:00:00+00:00</updated><content type="html">&lt;p&gt;Build tools add a lot of complexity. They solve real problems. But for small projects, they add layers of abstraction I don&amp;rsquo;t need. I want to write code and run it. No waiting for builds, no watching for changes, no debugging why the bundler failed.&lt;/p&gt;
&lt;p&gt;I wanted to test the React API without the build step. Preact is a good candidate: lightweight, same API, and it ships ES modules you can load directly in the browser. Combined with import maps, you get clean imports without a bundler.&lt;/p&gt;</content></entry><entry><title>Taming your shell for LLMs</title><link href="https://ricardoanderegg.com/posts/control-shell-permissions-llm-codex/" /><id>https://ricardoanderegg.com/posts/control-shell-permissions-llm-codex/</id><published>2025-09-26T00:00:00+00:00</published><updated>2025-09-26T00:00:00+00:00</updated><content type="html">&lt;p&gt;I recently got frustrated with Codex&amp;rsquo;s command permissions. They don&amp;rsquo;t let you configure which commands should always be allowed or denied. There&amp;rsquo;s &lt;a href="https://github.com/openai/codex/issues/1260"&gt;an issue&lt;/a&gt; about it, but it&amp;rsquo;s been open for almost 4 months as of writing this.&lt;/p&gt;
&lt;p&gt;Their sandboxing is less convenient than tools like Claude Code, since it&amp;rsquo;s more of an all or nothing approach. So I decided to build my own solution.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The Problem&lt;/h2&gt;
&lt;p&gt;To make LLM CLI agents useful, you need to let them run commands more freely, including ones with network access. But you want control over what they can execute. I think &amp;ldquo;Claude Code&amp;rdquo; has a very good user experience for this.&lt;/p&gt;</content></entry><entry><title>Stop reaching for file appends. Create new files instead.</title><link href="https://ricardoanderegg.com/posts/replace-file-append-with-new-files/" /><id>https://ricardoanderegg.com/posts/replace-file-append-with-new-files/</id><published>2025-09-15T00:00:00+00:00</published><updated>2025-09-15T00:00:00+00:00</updated><content type="html">&lt;p&gt;Creating new files is safer and simpler.&lt;/p&gt;
&lt;h2 id="the-problem-with-appending"&gt;The Problem with Appending&lt;/h2&gt;
&lt;p&gt;Appending to files causes problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multiple threads writing to the same file requires locks&lt;/li&gt;
&lt;li&gt;Other processes might append to the same file without you knowing about it (very rare, but could happen)&lt;/li&gt;
&lt;li&gt;Buffered writers don&amp;rsquo;t flush immediately&lt;/li&gt;
&lt;li&gt;Race conditions corrupt data&lt;/li&gt;
&lt;li&gt;Hard to debug when writes fail&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s hard to remove just part of the data&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="better-approach-create-new-files"&gt;Better Approach: Create New Files&lt;/h2&gt;
&lt;p&gt;Instead of appending, create one file per event/message/log entry.&lt;/p&gt;</content></entry><entry><title>Simple strategy to run Ansible tasks in parallel</title><link href="https://ricardoanderegg.com/posts/ansible-parallel-tasks-using-tags/" /><id>https://ricardoanderegg.com/posts/ansible-parallel-tasks-using-tags/</id><published>2025-03-05T00:00:00+00:00</published><updated>2025-03-05T00:00:00+00:00</updated><content type="html">&lt;p&gt;This post shows how to run some &lt;a href="https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_intro.html"&gt;Ansible playbook&lt;/a&gt; tasks in parallel. The approach requires &lt;strong&gt;tags&lt;/strong&gt; for all tasks you want to run in parallel.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How It Works&lt;/h2&gt;
&lt;p&gt;The script runs multiple Ansible tasks simultaneously by:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Defining a list of tags to run in parallel&lt;/li&gt;
&lt;li&gt;Using a &lt;a href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor"&gt;ThreadPoolExecutor&lt;/a&gt; to create a thread for each tag&lt;/li&gt;
&lt;li&gt;Running the Ansible playbook (as a subprocess) with a specific tag in each thread&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The example code (below) assumes the playbook files are part of the Python
package, and uses
&lt;a href="https://docs.python.org/3/library/importlib.resources.html"&gt;importlib.resources&lt;/a&gt;
to access them. But you can use any method to access the playbook files.&lt;/p&gt;</content></entry><entry><title>Why I use executable scripts instead of shell aliases</title><link href="https://ricardoanderegg.com/posts/executable-bin-scripts-instead-of-shell-aliases/" /><id>https://ricardoanderegg.com/posts/executable-bin-scripts-instead-of-shell-aliases/</id><published>2025-03-04T00:00:00+00:00</published><updated>2025-03-04T00:00:00+00:00</updated><content type="html">&lt;p&gt;I stopped using shell aliases and moved everything into executable scripts.&lt;/p&gt;
&lt;h2 id="main-benefits"&gt;Main Benefits&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;No need to source your &lt;code&gt;.bashrc&lt;/code&gt; after adding new scripts&lt;/li&gt;
&lt;li&gt;No need to edit &lt;code&gt;.bashrc&lt;/code&gt;, just drop executable files in your &lt;code&gt;~/bins&lt;/code&gt; folder (already in my &lt;code&gt;$PATH&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Use immediately without reloading your shell&lt;/li&gt;
&lt;li&gt;Faster iteration (edit script, re-run command, repeat).&lt;/li&gt;
&lt;li&gt;Available in more places:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Executable scripts in your &lt;code&gt;PATH&lt;/code&gt; can be used inside other scripts, sub-shells, &lt;code&gt;find -exec&lt;/code&gt;, &lt;code&gt;xargs -I{}&lt;/code&gt;, and other environments where the aliases defined in your &lt;code&gt;.bashrch&lt;/code&gt; are not read by default &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;</content></entry><entry><title>Exploiting Cursor to write better code</title><link href="https://ricardoanderegg.com/posts/cursor-ide-better-code-local-documentation/" /><id>https://ricardoanderegg.com/posts/cursor-ide-better-code-local-documentation/</id><published>2025-03-03T00:00:00+00:00</published><updated>2025-03-03T00:00:00+00:00</updated><content type="html">&lt;p&gt;I have been using the Cursor IDE for some time already and I really like its documentation indexing feature. Recently, I discovered a better way to leverage Cursor&amp;rsquo;s tools to make better references to official documentation and write better code.&lt;/p&gt;
&lt;h2 id="the-local-docs-advantage"&gt;The local docs advantage&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what I&amp;rsquo;ve been doing: Instead of relying on URL-indexed documentation, I download official docs directly to my machine. Take Caddy, for example. I grabbed their docs from &lt;a href="https://github.com/caddyserver/website"&gt;GitHub&lt;/a&gt; (see &lt;code&gt;src/docs/markdown&lt;/code&gt;), keeping just the markdown files in a local subfolder called &lt;code&gt;docs&lt;/code&gt;. Now when I&amp;rsquo;m tweaking my Caddy config, the documentation sits right next to my work.&lt;/p&gt;</content></entry><entry><title>ZIP as a bundle format</title><link href="https://ricardoanderegg.com/posts/zip-bundle-format/" /><id>https://ricardoanderegg.com/posts/zip-bundle-format/</id><published>2025-01-11T00:00:00+00:00</published><updated>2025-01-11T00:00:00+00:00</updated><content type="html">&lt;p&gt;At some point in the past, I created a tool for a project (not relevant for this post). This tool generated multiple artefacts from an input (embeddings file, JSON metadata, and other files). The project was successful, but one thing I didn&amp;rsquo;t like about the &amp;ldquo;tool&amp;rdquo; I wrote was that it was not easy to manage those artefacts. The artefacts had to be uploaded and downloaded to some remote(s). Apart from that, the code required all the files to be available, in the same directory, and in sync. For example, if you re-generated the embeddings, you had to re-generate the JSON metadata, but if you forgot to do so, or the process failed and didn&amp;rsquo;t notice, the tool wouldn&amp;rsquo;t work as expected.&lt;/p&gt;</content></entry><entry><title>From HTML template strings to elements</title><link href="https://ricardoanderegg.com/posts/from-html-template-strings-to-elements/" /><id>https://ricardoanderegg.com/posts/from-html-template-strings-to-elements/</id><published>2024-12-23T00:00:00+00:00</published><updated>2024-12-23T00:00:00+00:00</updated><content type="html">&lt;p&gt;Some time ago, I found (and used for a while) the &lt;a href="https://github.com/observablehq/htl"&gt;htl&lt;/a&gt; library. Before that, I was using raw &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals"&gt;template literals&lt;/a&gt; to build HTML, and then setting some &lt;code&gt;element.innerHTML = newString&lt;/code&gt;. &lt;code&gt;htl&lt;/code&gt; uses template literals, but instead returns a regular DOM Node object. This makes it a lot easier to add even listeners, setting other properties, and overall manipulating the object before appending it to the current document.&lt;/p&gt;
&lt;p&gt;I was curious to see how it was done, and it turns out it&amp;rsquo;s easier than I thought. The full library is a single &lt;a href="https://github.com/observablehq/htl/blob/e3e9777d09f7b5aea3ebc52e73b86a1246dcab7e/src/index.js"&gt;index.js&lt;/a&gt; file. Most of the code is parsing the HTML string to support different features from their &amp;ldquo;templating-format&amp;rdquo; (or that&amp;rsquo;s what I understood), which allows doing things like:&lt;/p&gt;</content></entry><entry><title>Handling keyboard shortcuts in JavaScript</title><link href="https://ricardoanderegg.com/posts/handle-keyboard-shortcuts-javascript/" /><id>https://ricardoanderegg.com/posts/handle-keyboard-shortcuts-javascript/</id><published>2024-12-21T00:00:00+00:00</published><updated>2024-12-21T00:00:00+00:00</updated><content type="html">&lt;p&gt;I was recently reading the source code of &lt;code&gt;mizu.js&lt;/code&gt;&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; and I liked the utility &amp;ldquo;function&amp;rdquo;&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt; they have to handle keyboard shortcuts/combinations. I decided to slightly modify it to have it as part of my JavaScript utility functions.&lt;/p&gt;
&lt;h2 id="the-function"&gt;The function&lt;/h2&gt;
&lt;p&gt;This function returns another function itself. You pass in a string that represents a combination of key presses like &lt;code&gt;Shift+Alt+C&lt;/code&gt;, and it returns a function that will return &lt;code&gt;true&lt;/code&gt; if a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent"&gt;KeyboardEvent&lt;/a&gt; matches that combination. I had to make some modifications to the original code. First, I converted it to JavaScript, because I don&amp;rsquo;t like having a build step, and I want to be able to copy-paste this code. I also changed the matcher on the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key"&gt;event.key&lt;/a&gt; to match on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code"&gt;event.code&lt;/a&gt; because I found &lt;code&gt;event.key&lt;/code&gt; was returning a string generated by the keyboard combination, not the actual key pressed.&lt;/p&gt;</content></entry><entry><title>Query a list of dictionaries with DuckDB</title><link href="https://ricardoanderegg.com/posts/duckdb-query-list-of-dictionaries-python-dict/" /><id>https://ricardoanderegg.com/posts/duckdb-query-list-of-dictionaries-python-dict/</id><published>2024-12-16T00:00:00+00:00</published><updated>2024-12-16T00:00:00+00:00</updated><content type="html">&lt;p&gt;How to query a list of Python dictionaries using DuckDB, without previously converting to another format.&lt;/p&gt;
&lt;p&gt;We can pass the list of dictionaries to the query directly and use &lt;a href="https://duckdb.org/docs/sql/query_syntax/unnest.html"&gt;unnest&lt;/a&gt; to convert to a list of rows. We can also expand the struct to multiple columns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: all the dictionaries must have the same keys.&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# /// script&lt;/span&gt;
&lt;span style="color: #8F5902; font-style: italic"&gt;# requires-python = &amp;quot;&amp;gt;=3.12&amp;quot;&lt;/span&gt;
&lt;span style="color: #8F5902; font-style: italic"&gt;# dependencies = [&amp;quot;duckdb&amp;quot;]&lt;/span&gt;
&lt;span style="color: #8F5902; font-style: italic"&gt;# ///&lt;/span&gt;

&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;duckdb&lt;/span&gt;


&lt;span style="color: #000"&gt;DATA&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000; font-weight: bold"&gt;[&lt;/span&gt;
    &lt;span style="color: #000; font-weight: bold"&gt;{&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #0000CF; font-weight: bold"&gt;1&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;some string&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;baz&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #0000CF; font-weight: bold"&gt;1.23&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;},&lt;/span&gt;
    &lt;span style="color: #000; font-weight: bold"&gt;{&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #0000CF; font-weight: bold"&gt;2&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;some other string&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;baz&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #0000CF; font-weight: bold"&gt;2.34&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;},&lt;/span&gt;
    &lt;span style="color: #000; font-weight: bold"&gt;{&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #0000CF; font-weight: bold"&gt;3&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;yet another string&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;baz&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #0000CF; font-weight: bold"&gt;3.45&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;},&lt;/span&gt;
&lt;span style="color: #000; font-weight: bold"&gt;]&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# Select as struct&lt;/span&gt;
&lt;span style="color: #000"&gt;rel&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;duckdb&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;query&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;SELECT unnest($data) as x&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;params&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;{&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #000"&gt;DATA&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;})&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# Expand struct to rows&lt;/span&gt;
&lt;span style="color: #000"&gt;rel&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;duckdb&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;query&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;SELECT x.* FROM (SELECT unnest($data) as x)&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;params&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;{&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #000"&gt;DATA&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;})&lt;/span&gt;

&lt;span style="color: #000"&gt;result&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;duckdb&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;query&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;SELECT * FROM rel WHERE foo &amp;gt; 1&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

&lt;span style="color: #204A87"&gt;print&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;result&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;fetchall&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;())&lt;/span&gt;
&lt;span style="color: #8F5902; font-style: italic"&gt;# [(2, &amp;#39;some other string&amp;#39;, 2.34), (3, &amp;#39;yet another string&amp;#39;, 3.45)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&amp;rsquo;s a longer script, including timings, and different approaches. I&amp;rsquo;m using &lt;code&gt;.fetchdf().to_markdown()&lt;/code&gt; to pretty-print the results:&lt;/p&gt;</content></entry><entry><title>Cron jobs inside your web app</title><link href="https://ricardoanderegg.com/posts/cron-jobs-inside-web-app-python/" /><id>https://ricardoanderegg.com/posts/cron-jobs-inside-web-app-python/</id><published>2024-12-13T00:00:00+00:00</published><updated>2024-12-13T00:00:00+00:00</updated><content type="html">&lt;p&gt;When you have a web application, almost always, you need to run some functions/scripts regularly. This what &lt;a href="https://en.wikipedia.org/wiki/Cron"&gt;cron&lt;/a&gt; is for. I wanted to find an easy way to run &amp;ldquo;cron-like&amp;rdquo; jobs inside a FastAPI app. The app runs inside docker, and I just need those jobs to run as long as the app is also running.&lt;/p&gt;
&lt;p&gt;Since the app is &amp;ldquo;async&amp;rdquo;, I found I can just have recurring background tasks as part of the app. We need to use the app &lt;a href="https://fastapi.tiangolo.com/advanced/events/"&gt;lifespan&lt;/a&gt; and some functions that run a task, the &lt;code&gt;asyncio.sleep&lt;/code&gt; for a pre-defined time. I decided to apply some random jitter to avoid multiple tasks starting at once. (Note: this can also be done in &amp;ldquo;sync&amp;rdquo; apps using threads).&lt;/p&gt;</content></entry><entry><title>My take on Web Components</title><link href="https://ricardoanderegg.com/posts/my-take-on-web-components/" /><id>https://ricardoanderegg.com/posts/my-take-on-web-components/</id><published>2024-12-12T00:00:00+00:00</published><updated>2024-12-12T00:00:00+00:00</updated><content type="html">&lt;p&gt;Lately, I&amp;rsquo;ve been trying to learn more JavaScript.&lt;/p&gt;
&lt;p&gt;I wanted to explore web components. After checking out some frameworks and tools, mainly &lt;a href="https://lit.dev/"&gt;lit&lt;/a&gt;, &lt;a href="https://tonicframework.dev/"&gt;tonic&lt;/a&gt; and &lt;a href="https://github.com/kgscialdone/facet"&gt;facet&lt;/a&gt;, I wanted to build my own thing.&lt;/p&gt;
&lt;p&gt;It ended up being heavily inspired by &lt;a href="https://tonicframework.dev/"&gt;tonic&lt;/a&gt;, but way simpler and with less features. I also really liked &lt;a href="https://github.com/lit/lit/tree/main/packages/lit-html"&gt;lit-html&lt;/a&gt;, which you can use as a separate package without having to use &lt;a href="https://lit.dev/"&gt;lit&lt;/a&gt;. It solves the problem of re-rendering only the UI parts that have changed, and it&amp;rsquo;s awesome at doing it.&lt;/p&gt;</content></entry><entry><title>DuckDB as a vector database</title><link href="https://ricardoanderegg.com/posts/duckdb-vector-database/" /><id>https://ricardoanderegg.com/posts/duckdb-vector-database/</id><published>2024-02-13T00:00:00+00:00</published><updated>2024-02-13T00:00:00+00:00</updated><content type="html">&lt;p&gt;DuckDB &lt;a href="https://duckdb.org/2024/02/13/announcing-duckdb-0100"&gt;version 0.10.0 has been released&lt;/a&gt;, bringing some new array functions. You can use them to turn DuckDB into a vector database. (Make sure you have at least version 0.10.0 of DuckDB version to follow &lt;code&gt;python3 -c "import duckdb; print(duckdb.__version__)"&lt;/code&gt;)&lt;/p&gt;
&lt;h2 id="insert-data-from-numpy-arrays"&gt;Insert data from numpy arrays&lt;/h2&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;duckdb&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;numpy&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;as&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;np&lt;/span&gt;

&lt;span style="color: #000"&gt;conn&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;duckdb&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;connect&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;database&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;:memory:&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;read_only&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;False&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

&lt;span style="color: #000"&gt;conn&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;CREATE TABLE data (id INTEGER, vector FLOAT4[768]);&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;


&lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;normalize&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;vec&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #000"&gt;np&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;ndarray&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color: #000"&gt;np&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;ndarray&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;return&lt;/span&gt; &lt;span style="color: #000"&gt;vec&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;/&lt;/span&gt; &lt;span style="color: #000"&gt;np&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;linalg&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;norm&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;vec&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;


&lt;span style="color: #8F5902; font-style: italic"&gt;# insert 3000 random vectors, each vector has 768 dimensions&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;for&lt;/span&gt; &lt;span style="color: #000"&gt;i&lt;/span&gt; &lt;span style="color: #204A87; font-weight: bold"&gt;in&lt;/span&gt; &lt;span style="color: #204A87"&gt;range&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold"&gt;3000&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
    &lt;span style="color: #000"&gt;vector&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;np&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;random&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;rand&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold"&gt;768&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;astype&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;float32&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
    &lt;span style="color: #8F5902; font-style: italic"&gt;# normalize vector before inserting&lt;/span&gt;
    &lt;span style="color: #000"&gt;norm_vector&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;normalize&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;vector&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
    &lt;span style="color: #000"&gt;conn&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;INSERT INTO data VALUES (?, ?)&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;i&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;vector&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Some notes about datatypes:&lt;/p&gt;</content></entry><entry><title>Building HTML components from Python functions</title><link href="https://ricardoanderegg.com/posts/python-build-html-components-lxml/" /><id>https://ricardoanderegg.com/posts/python-build-html-components-lxml/</id><published>2024-01-11T00:00:00+00:00</published><updated>2024-01-11T00:00:00+00:00</updated><content type="html">&lt;p&gt;This post could also be called &amp;ldquo;Or how to do React in Python&amp;rdquo; or &amp;ldquo;HTML as a function of state&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Most people use templating libraries like &lt;a href="https://jinja.palletsprojects.com/"&gt;jinja2&lt;/a&gt; to render HTML. I think that&amp;rsquo;s probably the best way to do it in production. However, for very simple / internal / proof-of-concept apps, I wanted to generate the HTML directly from Python functions to avoid needing extra files. I tried using f-strings to do that, but it gets messy pretty quickly. I recently found a nice way to render HTML using &lt;a href="https://lxml.de/"&gt;lxml&lt;/a&gt;. As a nice side effect, the overall architecture is similar to React, where functions become UI components. At the same time, it allows rendering only individual components easily. This can be especially useful when used together with &lt;a href="https://htmx.org/"&gt;HTMX&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>Python profiling and timing utils</title><link href="https://ricardoanderegg.com/posts/python-profiling-timing-utils/" /><id>https://ricardoanderegg.com/posts/python-profiling-timing-utils/</id><published>2023-09-08T00:00:00+00:00</published><updated>2023-09-08T00:00:00+00:00</updated><content type="html">&lt;p&gt;These are just a few Python snippets that I have been using a lot for timing and profiling functions using only the standard library. You can also find the code here as a &lt;a href="https://gist.github.com/polyrand/bb39fb93246ced7464abf52d87fec3a7"&gt;GitHub Gist&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;contextlib&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;from&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;functools&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt; &lt;span style="color: #000"&gt;wraps&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;cProfile&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;from&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;typing&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt; &lt;span style="color: #000"&gt;Optional&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;io&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;pstats&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;time&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;from&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;pathlib&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt; &lt;span style="color: #000"&gt;Path&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;from&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;functools&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt; &lt;span style="color: #000"&gt;wraps&lt;/span&gt;


&lt;span style="color: #5C35CC; font-weight: bold"&gt;@contextlib&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;contextmanager&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;profile&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;filename&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #000"&gt;Path&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;*&lt;/span&gt;&lt;span style="color: #000"&gt;args&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;**&lt;/span&gt;&lt;span style="color: #000"&gt;kwargs&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
    &lt;span style="color: #000"&gt;profile&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;cProfile&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;Profile&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;*&lt;/span&gt;&lt;span style="color: #000"&gt;args&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;**&lt;/span&gt;&lt;span style="color: #000"&gt;kwargs&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

    &lt;span style="color: #000"&gt;profile&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;enable&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;yield&lt;/span&gt;
    &lt;span style="color: #000"&gt;profile&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;disable&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt;

    &lt;span style="color: #000"&gt;s&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;io&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;StringIO&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt;
    &lt;span style="color: #000"&gt;sortby&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;pstats&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;SortKey&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;CUMULATIVE&lt;/span&gt;
    &lt;span style="color: #000"&gt;ps&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;pstats&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;Stats&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;profile&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;stream&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #000"&gt;s&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;strip_dirs&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;sort_stats&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;sortby&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
    &lt;span style="color: #000"&gt;ps&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;print_stats&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;with&lt;/span&gt; &lt;span style="color: #204A87"&gt;open&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;filename&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;with_suffix&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;.txt&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;),&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;w&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt; &lt;span style="color: #204A87; font-weight: bold"&gt;as&lt;/span&gt; &lt;span style="color: #000"&gt;f&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt;
        &lt;span style="color: #000"&gt;f&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;write&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;s&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;getvalue&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;())&lt;/span&gt;

    &lt;span style="color: #000"&gt;profile&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;dump_stats&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;filename&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;with_suffix&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;.prof&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;))&lt;/span&gt;


&lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;profiled&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;name&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #000"&gt;Path&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;decorator&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;fn&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
        &lt;span style="color: #5C35CC; font-weight: bold"&gt;@wraps&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;fn&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
        &lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;wrapper&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;*&lt;/span&gt;&lt;span style="color: #000"&gt;args&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;**&lt;/span&gt;&lt;span style="color: #000"&gt;kwargs&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
            &lt;span style="color: #204A87; font-weight: bold"&gt;with&lt;/span&gt; &lt;span style="color: #000"&gt;profile&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;name&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
                &lt;span style="color: #204A87; font-weight: bold"&gt;return&lt;/span&gt; &lt;span style="color: #000"&gt;fn&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;*&lt;/span&gt;&lt;span style="color: #000"&gt;args&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;**&lt;/span&gt;&lt;span style="color: #000"&gt;kwargs&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

        &lt;span style="color: #204A87; font-weight: bold"&gt;return&lt;/span&gt; &lt;span style="color: #000"&gt;wrapper&lt;/span&gt;

    &lt;span style="color: #204A87; font-weight: bold"&gt;return&lt;/span&gt; &lt;span style="color: #000"&gt;decorator&lt;/span&gt;


&lt;span style="color: #5C35CC; font-weight: bold"&gt;@contextlib&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;contextmanager&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;timeit&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;output_file&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #000"&gt;Optional&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;[&lt;/span&gt;&lt;span style="color: #000"&gt;Path&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;]&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #204A87; font-weight: bold"&gt;None&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
    &lt;span style="color: #000"&gt;start&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;time&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;perf_counter&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;yield&lt;/span&gt;
    &lt;span style="color: #000"&gt;end&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;time&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;perf_counter&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;if&lt;/span&gt; &lt;span style="color: #000"&gt;output_file&lt;/span&gt; &lt;span style="color: #204A87; font-weight: bold"&gt;is&lt;/span&gt; &lt;span style="color: #204A87; font-weight: bold"&gt;not&lt;/span&gt; &lt;span style="color: #204A87; font-weight: bold"&gt;None&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt;
        &lt;span style="color: #204A87; font-weight: bold"&gt;with&lt;/span&gt; &lt;span style="color: #204A87"&gt;open&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;output_file&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt; &lt;span style="color: #204A87; font-weight: bold"&gt;as&lt;/span&gt; &lt;span style="color: #000"&gt;f&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt;
            &lt;span style="color: #000"&gt;f&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;write&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;f&amp;quot;{&lt;/span&gt;&lt;span style="color: #000"&gt;end&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;-&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;start&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;}\n&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;else&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt;
        &lt;span style="color: #204A87"&gt;print&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;f&amp;quot;{&lt;/span&gt;&lt;span style="color: #000"&gt;end&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;-&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;start&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;}&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;


&lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;timed&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;output_file&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #000"&gt;Optional&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;[&lt;/span&gt;&lt;span style="color: #000"&gt;Path&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;]&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #204A87; font-weight: bold"&gt;None&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;decorator&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;fn&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
        &lt;span style="color: #5C35CC; font-weight: bold"&gt;@wraps&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;fn&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
        &lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;wrapper&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;*&lt;/span&gt;&lt;span style="color: #000"&gt;args&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;**&lt;/span&gt;&lt;span style="color: #000"&gt;kwargs&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
            &lt;span style="color: #204A87; font-weight: bold"&gt;with&lt;/span&gt; &lt;span style="color: #000"&gt;timeit&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;output_file&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
                &lt;span style="color: #204A87; font-weight: bold"&gt;return&lt;/span&gt; &lt;span style="color: #000"&gt;fn&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;*&lt;/span&gt;&lt;span style="color: #000"&gt;args&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;**&lt;/span&gt;&lt;span style="color: #000"&gt;kwargs&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

        &lt;span style="color: #204A87; font-weight: bold"&gt;return&lt;/span&gt; &lt;span style="color: #000"&gt;wrapper&lt;/span&gt;

    &lt;span style="color: #204A87; font-weight: bold"&gt;return&lt;/span&gt; &lt;span style="color: #000"&gt;decorator&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="usage"&gt;Usage&lt;/h2&gt;
&lt;p&gt;You can use a context manager or the decorator both for profiling and timing&lt;/p&gt;</content></entry><entry><title>Replacing FFI with a CLI</title><link href="https://ricardoanderegg.com/posts/replace-ffi-cli-subprocess-call/" /><id>https://ricardoanderegg.com/posts/replace-ffi-cli-subprocess-call/</id><published>2023-07-23T18:00:00+00:00</published><updated>2023-07-23T18:00:00+00:00</updated><content type="html">&lt;p&gt;I recently read a post from vercel about &lt;a href="https://vercel.com/blog/how-turborepo-is-porting-from-go-to-rust"&gt;porting turborepo to rust&lt;/a&gt;. In that post, they mention calling a &lt;code&gt;go&lt;/code&gt; binary from the rust code instead of having to deal with FFI and &lt;code&gt;C&lt;/code&gt; type compatibility.&lt;/p&gt;
&lt;p&gt;I wrote a post called &amp;ldquo;&lt;a href="/posts/subprocess-instead-of-dependency"&gt;Use a subprocess instead of a dependency&lt;/a&gt;&amp;rdquo;, which follows a similar philosophy, although applied to something different. Here are some extra notes related to the vercel post. As an example, I&amp;rsquo;ll use a Python app that wants to call some Rust code, but the idea could apply to any combination.&lt;/p&gt;</content></entry><entry><title>macOS port 5000 not working</title><link href="https://ricardoanderegg.com/posts/macos-port-5000-not-working/" /><id>https://ricardoanderegg.com/posts/macos-port-5000-not-working/</id><published>2023-07-23T12:00:00+00:00</published><updated>2023-07-23T12:00:00+00:00</updated><content type="html">&lt;p&gt;macOS AirPlay Receiver now listens on port &lt;code&gt;5000&lt;/code&gt; by default, which conflicts with the default port used by some frameworks (like &lt;code&gt;Flask&lt;/code&gt;). This may cause some confusion if you&amp;rsquo;re trying to forward port 5000 from a different VM machine and you don&amp;rsquo;t see anything in your browser.&lt;/p&gt;
&lt;p&gt;To fix it, you need to uncheck the option in System Preferences -&amp;gt; Sharing -&amp;gt; AirPlay Receiver. Then it works again, otherwise, if you try to make something listen on port &lt;code&gt;5000&lt;/code&gt; it may not work&lt;/p&gt;</content></entry><entry><title>Named parameters in shell scripts and Makefiles</title><link href="https://ricardoanderegg.com/posts/named-parameters-shell-scripts-makefiles/" /><id>https://ricardoanderegg.com/posts/named-parameters-shell-scripts-makefiles/</id><published>2023-05-21T00:00:00+00:00</published><updated>2023-05-21T00:00:00+00:00</updated><content type="html">&lt;p&gt;I recently learned &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; a nice pattern to improve parameter handling in shell scripts. The pattern involves parameter expansion:&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span style="color: #204A87"&gt;set&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;-euo&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;pipefail

&lt;span style="color: #204A87; font-weight: bold"&gt;function&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;main&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;{&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #204A87"&gt;local&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;arg1&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;${&lt;/span&gt;&lt;span style="color: #000"&gt;A1&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:?&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;#39;FAIL. Provide A1 var&amp;#39;}&amp;quot;&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #204A87"&gt;echo&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;$arg1&lt;/span&gt;
&lt;span style="color: #CE5C00; font-weight: bold"&gt;}&lt;/span&gt;


main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When calling the script (called &lt;code&gt;t.sh&lt;/code&gt; throughout this post), it will fail:&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;bash&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;t.sh
&lt;span style="color: #8F5902; font-style: italic"&gt;# t.sh: line 7: A1: FAIL. Provide A1 var&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But this will succeed:&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #000"&gt;A1&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;foo&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;bash&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;t.sh
&lt;span style="color: #8F5902; font-style: italic"&gt;# foo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It can also be used to provide default/required positional arguments.&lt;/p&gt;</content></entry><entry><title>Makefile tricks for Python projects</title><link href="https://ricardoanderegg.com/posts/makefile-python-project-tricks/" /><id>https://ricardoanderegg.com/posts/makefile-python-project-tricks/</id><published>2023-05-19T00:00:00+00:00</published><updated>2023-05-19T00:00:00+00:00</updated><content type="html">&lt;p&gt;I like using Makefiles. They work great both as simple task runners as well as build systems for medium-size projects. This is my starter template for Python projects.&lt;/p&gt;
&lt;p&gt;Note: This blog post assumes some basic knowledge of how &lt;code&gt;make&lt;/code&gt; and Makefiles work.&lt;/p&gt;
&lt;h2 id="basic-configuration"&gt;Basic configuration&lt;/h2&gt;
&lt;p&gt;I like using bash as the default shell. Then set some flags to exit on error (&lt;code&gt;-eu -o pipefail&lt;/code&gt;), warn about undefined variables and disable built-in rules.&lt;/p&gt;</content></entry><entry><title>Using IPython for timing and profiling</title><link href="https://ricardoanderegg.com/posts/ipython-timing-profiling-script/" /><id>https://ricardoanderegg.com/posts/ipython-timing-profiling-script/</id><published>2023-04-18T00:00:00+00:00</published><updated>2023-04-18T00:00:00+00:00</updated><content type="html">&lt;h2 id="before-you-read"&gt;Before you read&lt;/h2&gt;
&lt;p&gt;I found out the code here doesn&amp;rsquo;t work outside IPython, I didn&amp;rsquo;t realize that &lt;code&gt;get_ipython()&lt;/code&gt; only works when running inside IPython. But the examples here work in isolated scripts if you run the script using ipython: &lt;code&gt;ipython benchmarh.py&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I like using IPython to measure the execution time of Python functions. You can also time functions using the &lt;a href="https://docs.python.org/3/library/timeit.html"&gt;timeit&lt;/a&gt; module, but the &lt;a href="https://ipython.readthedocs.io/en/stable/"&gt;IPython&lt;/a&gt; utilities are just more convenient, and I install IPython in almost all my virtual environments anyway.&lt;/p&gt;</content></entry><entry><title>Validate Python dataclass types</title><link href="https://ricardoanderegg.com/posts/python-validate-dataclass-types/" /><id>https://ricardoanderegg.com/posts/python-validate-dataclass-types/</id><published>2023-03-21T00:00:00+00:00</published><updated>2023-03-21T00:00:00+00:00</updated><content type="html">&lt;p&gt;In Python you can create &lt;code&gt;dataclasses&lt;/code&gt; with the wrong type. The type checker should show an error, but nothing prevents creating the object. This small function validates that each attribute is of the correct type by using the &lt;code&gt;__annotations__&lt;/code&gt; attribute of the &lt;code&gt;dataclass&lt;/code&gt;. You can also create a base class to inherit from, but it won&amp;rsquo;t work if you override the &lt;code&gt;__post_init__&lt;/code&gt; method in the child classes.&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;dataclasses&lt;/span&gt;


&lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;val&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;t&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span style="color: #8F5902; font-style: italic"&gt;    Validate the object `t` types based on the&lt;/span&gt;
&lt;span style="color: #8F5902; font-style: italic"&gt;    __annotations__ dictionary.&lt;/span&gt;
&lt;span style="color: #8F5902; font-style: italic"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;for&lt;/span&gt; &lt;span style="color: #000"&gt;k&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt;&lt;span style="color: #000"&gt;v&lt;/span&gt; &lt;span style="color: #204A87; font-weight: bold"&gt;in&lt;/span&gt; &lt;span style="color: #000"&gt;t&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;__annotations__&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;items&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;():&lt;/span&gt;
        &lt;span style="color: #204A87; font-weight: bold"&gt;assert&lt;/span&gt; &lt;span style="color: #204A87"&gt;isinstance&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #204A87"&gt;getattr&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;t&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;k&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;),&lt;/span&gt; &lt;span style="color: #000"&gt;v&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;


&lt;span style="color: #8F5902; font-style: italic"&gt;#Base class&lt;/span&gt;
&lt;span style="color: #5C35CC; font-weight: bold"&gt;@dataclasses&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;dataclass&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;frozen&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;True&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;slots&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;True&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;class&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;Base&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;__post_init__&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #3465A4"&gt;self&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
        &lt;span style="color: #000"&gt;val&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #3465A4"&gt;self&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# Inherit from base class&lt;/span&gt;
&lt;span style="color: #5C35CC; font-weight: bold"&gt;@dataclasses&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;dataclass&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;frozen&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;True&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;slots&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;True&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;class&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;User&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;Base&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
    &lt;span style="color: #000"&gt;name&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #204A87"&gt;str&lt;/span&gt;
    &lt;span style="color: #000"&gt;age&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #204A87"&gt;int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now when initializing the object, it will throw a &lt;strong&gt;runtime&lt;/strong&gt; exception if any of the attributes is not of the correct type.&lt;/p&gt;</content></entry><entry><title>Using mmap to share data between processes</title><link href="https://ricardoanderegg.com/posts/mmap-share-data-between-processes/" /><id>https://ricardoanderegg.com/posts/mmap-share-data-between-processes/</id><published>2023-03-20T00:00:00+00:00</published><updated>2023-03-20T00:00:00+00:00</updated><content type="html">&lt;p&gt;As part of my recent experiments with mmap&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; I have learned how to share data between processes using a memory-mapped file. Here I&amp;rsquo;ll show how to do it between two independent Python processes, but the same principles apply to any programming language.&lt;/p&gt;
&lt;h2 id="create-a-file-to-store-the-data"&gt;Create a file to store the data&lt;/h2&gt;
&lt;p&gt;I will use the &lt;code&gt;tempfile&lt;/code&gt; module so that the file gets deleted after the script finishes. I prefer using this when learning or testing new things, otherwise my folders end up filled with random files. You can also use another location instead of the temporary file.
We need to know where this file is stored. We can use the &lt;code&gt;.name&lt;/code&gt; attribute of the temporary file to get its path. Note that this will change every time you re-run the script because the files are temporary.&lt;/p&gt;</content></entry><entry><title>Running regexes on memory-mapped files</title><link href="https://ricardoanderegg.com/posts/python-regex-mmap-memory-mapped-file/" /><id>https://ricardoanderegg.com/posts/python-regex-mmap-memory-mapped-file/</id><published>2023-03-17T00:00:00+00:00</published><updated>2023-03-17T00:00:00+00:00</updated><content type="html">&lt;p&gt;Here are some benchmarks I ran to compare the speed of running a list of regexes on all the Markdown files in my Obsidian folder (210 when I wrote this). The benchmark compares running the regexes on memory-mapped files versus loading the file contents as a string and running the regexes on that string. I&amp;rsquo;m using &lt;a href="https://github.com/sharkdp/hyperfine"&gt;hyperfine&lt;/a&gt; to run the benchmarks.&lt;/p&gt;
&lt;h2 id="considerations"&gt;Considerations&lt;/h2&gt;
&lt;p&gt;When we memory-map a file, we work with bytes. Python can run regexes over those bytes too, but the pattern has to be &lt;code&gt;.encode()&lt;/code&gt;&amp;lsquo;ed for it to work.&lt;/p&gt;</content></entry><entry><title>Moving from Apple Notes to Obsidian</title><link href="https://ricardoanderegg.com/posts/apple-notes-to-obsidian/" /><id>https://ricardoanderegg.com/posts/apple-notes-to-obsidian/</id><published>2023-03-14T00:00:00+00:00</published><updated>2023-03-14T00:00:00+00:00</updated><content type="html">&lt;p&gt;After trying a few note-taking apps, I ended up using Apple Notes. It was super fast on macOS and iOS. This was more or less my thinking:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/img/s/apple-notes-meme.png"&gt;&lt;/p&gt;
&lt;p&gt;The syncing was good and it worked offline. But it had a couple of drawbacks. The format is not open. There are some scripts to reverse-engineer the Apple Notes SQLite database&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;, but that still needs a computer with iCloud sync, otherwise you can&amp;rsquo;t get the Notes.app SQLite database on your disk.&lt;/p&gt;</content></entry><entry><title>This is now a stream of my thoughts</title><link href="https://ricardoanderegg.com/posts/stream-of-thoughts-notes/" /><id>https://ricardoanderegg.com/posts/stream-of-thoughts-notes/</id><published>2023-03-14T00:00:00+00:00</published><updated>2023-03-14T00:00:00+00:00</updated><content type="html">&lt;p&gt;This blog started as a place to share new things I learned about programming. I initially wrote Jupyter notebooks that I converted to Markdown. Then I started writing Markdown directly.&lt;/p&gt;
&lt;p&gt;After some time, I felt like having to open my text editor in my laptop to write a blog post was making me write less. It also felt like I had to write something longer than a tweet. That&amp;rsquo;s how I started using Apple Notes a lot more&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;. Some notes were long, others were shorter than a Tweet. I&amp;rsquo;ve been enjoying this, so I decided to take a similar approach with my website. Instead of just publishing posts that I&amp;rsquo;ve thought about and re-read multiple times, I will also make my TILs (Today I Learned), small code snippets, quick benchmarks, random thoughts about work and life, etc. public.&lt;/p&gt;</content></entry><entry><title>Using Apple Notes as a CMS</title><link href="https://ricardoanderegg.com/posts/apple-notes-blog-cms/" /><id>https://ricardoanderegg.com/posts/apple-notes-blog-cms/</id><published>2023-03-14T00:00:00+00:00</published><updated>2023-03-14T00:00:00+00:00</updated><content type="html">&lt;h2 id="intro"&gt;Intro&lt;/h2&gt;
&lt;p&gt;I was exploring different ways I could use Apple Notes as a CMS (Content Management System). I found out that you can add a Google account to sync some notes, but those notes are synced using the IMAP protocol to a folder in the email account. This post explains how to use the Gmail API to retrieve those notes. The idea for the CMS is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write notes in Apple Notes, avoid using tables and drawings (there may be other elements that are not compatible with this method)&lt;/li&gt;
&lt;li&gt;Add a new Google account and synchronize the notes&lt;/li&gt;
&lt;li&gt;Duplicate the note you want to sync and move it to the Google account folder in the Notes app.&lt;/li&gt;
&lt;li&gt;Use the Gmail API to retrieve the note programatically from another server.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;My main objective was being able to read my notes from a linux computer that doesn&amp;rsquo;t have access to iCloud. This is how I did it.&lt;/p&gt;</content></entry><entry><title>Using SQLite for logging and ad-hoc profiling</title><link href="https://ricardoanderegg.com/posts/sqlite-logging-profiling-programs/" /><id>https://ricardoanderegg.com/posts/sqlite-logging-profiling-programs/</id><published>2023-03-12T00:00:00+00:00</published><updated>2023-03-12T00:00:00+00:00</updated><content type="html">&lt;p&gt;I was recently reading the documentation of &lt;a href="https://github.com/nnethercote/counts"&gt;nnethercote/counts&lt;/a&gt;, in there, Nicholas explains a few pain points when using a table as a profiling output. But using SQLite as the “table” can relieve some of those pains. I frequently use SQLite for debugging and I wanted to share some techniques that have been helpful (and relate them to &lt;a href="https://github.com/nnethercote/counts#worse-is-better"&gt;some arguments mentioned in nnethercore/counts&lt;/a&gt;)&lt;/p&gt;
&lt;h2 id="defining-the-table-and-exposing-it-to-multiple-modules"&gt;Defining the table and exposing it to multiple modules&lt;/h2&gt;
&lt;p&gt;These 2 points are not a problem with SQLite, the “table” is a file outside your program, any module can write to it or read from it.&lt;/p&gt;</content></entry><entry><title>Python automation utils</title><link href="https://ricardoanderegg.com/posts/python-automation-utils/" /><id>https://ricardoanderegg.com/posts/python-automation-utils/</id><published>2023-03-11T00:00:00+00:00</published><updated>2023-03-11T00:00:00+00:00</updated><content type="html">&lt;p&gt;Here are some utility functions that have been useful when writing automation scripts.&lt;/p&gt;
&lt;h2 id="requests"&gt;requests&lt;/h2&gt;
&lt;p&gt;I like using &lt;a href="https://requests.readthedocs.io/en/latest/"&gt;requests&lt;/a&gt; or &lt;a href="https://www.python-httpx.org/"&gt;httpx&lt;/a&gt;, but if you add a dependency to your script, now you&amp;rsquo;ll need to create an environment, install the depdencies, etc. just to run it. I like keeping automation scripts in a single file I can copy around. Instead of using the &lt;code&gt;requests&lt;/code&gt;, module, you can use this. This function has been adapted from the &lt;code&gt;urlrequest&lt;/code&gt; function in &lt;a href="https://github.com/fastai/fastcore"&gt;fastai/fastcore&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>Stream a CSV from S3 to a parquet file</title><link href="https://ricardoanderegg.com/posts/stream-csv-s3-parquet-local-file/" /><id>https://ricardoanderegg.com/posts/stream-csv-s3-parquet-local-file/</id><published>2023-03-11T00:00:00+00:00</published><updated>2023-03-11T00:00:00+00:00</updated><content type="html">&lt;p&gt;I wanted to query a large TSV file stored in S3. To achieve this, I decided to convert it to Parquet and query it using &lt;a href="https://duckdb.org/"&gt;DuckDB&lt;/a&gt;. However, I didn&amp;rsquo;t want to download the full file and then convert it. Instead, I wanted to stream the CSV file directly from S3 and write the output to a Parquet file. Here are a couple of approaches that worked quite nicely.&lt;/p&gt;
&lt;h2 id="setup"&gt;Setup&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m running these experiments on an EC2 instance with 8 cores and 32GB of RAM. The data is stored in a 700GB &lt;code&gt;gp2&lt;/code&gt; volume with 2100 IOPS.&lt;/p&gt;</content></entry><entry><title>Use a subprocess instead of a dependency</title><link href="https://ricardoanderegg.com/posts/subprocess-instead-of-dependency/" /><id>https://ricardoanderegg.com/posts/subprocess-instead-of-dependency/</id><published>2023-03-11T00:00:00+00:00</published><updated>2023-03-11T00:00:00+00:00</updated><content type="html">&lt;p&gt;Sometimes calling a subprocess is better than using a dependency/package. At least in Python, once you add a third-party dependency, distribution becomes slightly harder. I like writing automation scripts in a single &lt;code&gt;.py&lt;/code&gt; file. If that script doesn&amp;rsquo;t use any third-party dependencies, distributing it is as easy as copying the file to the machine. Otherwise you need to package your project, deal with virtual environments, PyPi, &lt;a href="https://github.com/pypa/pipx"&gt;pipx&lt;/a&gt;, etc. I don&amp;rsquo;t think all of those tasks are hard, but &lt;code&gt;rsync&lt;/code&gt;&amp;lsquo;ing a file is easier.&lt;/p&gt;</content></entry><entry><title>Passing arrays as parameters to SQLite</title><link href="https://ricardoanderegg.com/posts/sqlite-list-array-parameter-query/" /><id>https://ricardoanderegg.com/posts/sqlite-list-array-parameter-query/</id><published>2022-08-30T00:00:00+00:00</published><updated>2022-08-30T00:00:00+00:00</updated><content type="html">&lt;h2 id="tldr"&gt;tl;dr&lt;/h2&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;conn.execute&lt;span style="color: #CE5C00; font-weight: bold"&gt;(&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;select * from ... where ... in (select value from json_each(?))&amp;quot;&lt;/span&gt;,
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;(&lt;/span&gt;json.dumps&lt;span style="color: #CE5C00; font-weight: bold"&gt;(&lt;/span&gt;list_of_values&lt;span style="color: #CE5C00; font-weight: bold"&gt;)&lt;/span&gt;,&lt;span style="color: #CE5C00; font-weight: bold"&gt;)&lt;/span&gt;,
&lt;span style="color: #CE5C00; font-weight: bold"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="lists-of-values-in-sqlite"&gt;Lists of values in SQLite&lt;/h2&gt;
&lt;p&gt;SQLite doesn’t have an array type as Postgres does, but we can exploit the JSON extension to do operations with arrays.&lt;/p&gt;
&lt;p&gt;An example of why this may be needed. Let&amp;rsquo;s say you have a table with names, and you want to select all the &lt;code&gt;id&lt;/code&gt;&amp;rsquo;s of people from a list of names. Something like:&lt;/p&gt;</content></entry><entry><title>Musings about automation</title><link href="https://ricardoanderegg.com/posts/musings-thoughts-software-automation/" /><id>https://ricardoanderegg.com/posts/musings-thoughts-software-automation/</id><published>2022-08-14T00:00:00+00:00</published><updated>2022-08-14T00:00:00+00:00</updated><content type="html">&lt;p&gt;Engineers like automating tasks. You find yourself running a set of commands, copying values between files and prompts, and you think &lt;em&gt;I can automate this!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Aside from the joke: “why spend 30 minutes doing something when you can spend 2 days writing a program to automate it”, I believe we don’t think enough about automation. Here I want to share some ideas.&lt;/p&gt;
&lt;h2 id="broken-automation-is-more-painful-than-manual-work"&gt;Broken automation is more painful than manual work&lt;/h2&gt;
&lt;p&gt;Automation is wonderful &lt;a href="https://twitter.com/Atlassian/status/1511870509973090304"&gt;until it breaks&lt;/a&gt;. When that happens, the fix may be easy, but maybe, having the automation in place made you forget how that task is actually done. Now you have to spend time reading code and understanding all the parts of the process. This may take a few minutes or a few days.&lt;/p&gt;</content></entry><entry><title>The unreasonable developer experience of SQLite</title><link href="https://ricardoanderegg.com/posts/sqlite-developer-experience/" /><id>https://ricardoanderegg.com/posts/sqlite-developer-experience/</id><published>2022-08-10T00:00:00+00:00</published><updated>2022-08-10T00:00:00+00:00</updated><content type="html">&lt;p&gt;In this post, I want to share some reasons why using SQLite turns into a pretty convenient developer experience.&lt;/p&gt;
&lt;p&gt;This is a “live” post that may be updated in the future with more contents.&lt;/p&gt;
&lt;h2 id="moving-and-sharing-data-backups"&gt;Moving and sharing data, backups&lt;/h2&gt;
&lt;p&gt;Sharing SQLite data is straightforward, just rsync the file to a new VM or upload it to any file storage service. When you want to share data from other databases, it usually requires generating an SQL dump of the data. Then, as a consumer of the data, you&amp;rsquo;re responsible for starting a DB server and loading the dump. You also need to know if the DB versions are compatible. The SQLite format has been stable for years, so older versions of SQLite can open databases generated with newer versions.&lt;/p&gt;</content></entry><entry><title>Building a remote SQLite explorer</title><link href="https://ricardoanderegg.com/posts/sqlite-remote-explorer-gui/" /><id>https://ricardoanderegg.com/posts/sqlite-remote-explorer-gui/</id><published>2022-06-23T00:00:00+00:00</published><updated>2022-06-23T00:00:00+00:00</updated><content type="html">&lt;p&gt;One of the main pain points of using SQLite in production deployments or VMs is managing the database. There are lots of database GUIs, but only work with local SQLite databases. Managing an SQLite database remotely requires:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adding a new service to the deployment (like &lt;a href="https://www.adminer.org/"&gt;Adminer&lt;/a&gt;, &lt;a href="https://github.com/coleifer/sqlite-web"&gt;sqlite-web&lt;/a&gt; or &lt;a href="https://github.com/benbjohnson/postlite"&gt;postlite&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Giving the new service permissions to access the volume with the database&lt;/li&gt;
&lt;li&gt;Exposing a port to access the service
  The alternative is usually SSH’ing to the remote VM and use the sqlite3 CLI to manage or explore the database.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this in mind, I decided to build a remote SQLite management GUI that does &lt;strong&gt;not&lt;/strong&gt; require running any service in the remote VM and only needs an SSH connection between you and the remote machine.&lt;/p&gt;</content></entry><entry><title>Peeking and backtracking Python generators</title><link href="https://ricardoanderegg.com/posts/peeking-backtracking-python-generator/" /><id>https://ricardoanderegg.com/posts/peeking-backtracking-python-generator/</id><published>2022-05-28T00:00:00+00:00</published><updated>2022-05-28T00:00:00+00:00</updated><content type="html">&lt;p&gt;Python generators are mighty, but they lack a couple of useful features. One of them is peeking the next item without consuming the generator. Even better, what if we could peek any number of items? Another feature lacking from generators is rewinding/backtracking. We will implement both of those features in a couple of different ways. Note: if you need a better tested implementation that lets you peek 1 item, check out &lt;a href="https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.peekable"&gt;more_itertools.peekable&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>Extending SQLite with Rust</title><link href="https://ricardoanderegg.com/posts/extending-sqlite-with-rust/" /><id>https://ricardoanderegg.com/posts/extending-sqlite-with-rust/</id><published>2022-05-15T00:00:00+00:00</published><updated>2022-05-15T00:00:00+00:00</updated><content type="html">&lt;p&gt;SQLite has a powerful extension mechanism: &lt;a href="https://www.sqlite.org/loadext.html"&gt;loadable extensions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Being an in-process database, SQLite has other extensions mechanisms like &lt;a href="https://www.sqlite.org/appfunc.html"&gt;application-defined functions&lt;/a&gt; (UDF for short). But UDFs have some shortcomings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They’re local to an SQLite connection, not shared for every process connected to the DB&lt;/li&gt;
&lt;li&gt;They have to be defined in your program. That means that you need to have the function available in the same scope as your application.
  This is where loadable extensions come in. Loadable extensions can be written in any programming language that can be compiled to a shared library/DLL. Then you can just share the compiled object and load them from any application or programming language. In this post, we’ll see how we can use &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt; to write an SQLite loadable extension.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="intro"&gt;Intro&lt;/h2&gt;
&lt;p&gt;This post is a simplified version of some techniques I learned from &lt;a href="https://github.com/phiresky/sqlite-zstd"&gt;phiresky/sqlite-zstd&lt;/a&gt;. That is an SQLite extension that enables zstd compression on SQLite, I highly recommend checking it out if you want to look at more advanced examples than this post.&lt;/p&gt;</content></entry><entry><title>Python, SQLite, and thread safety</title><link href="https://ricardoanderegg.com/posts/python-sqlite-thread-safety/" /><id>https://ricardoanderegg.com/posts/python-sqlite-thread-safety/</id><published>2022-04-04T00:00:00+00:00</published><updated>2022-04-04T00:00:00+00:00</updated><content type="html">&lt;p&gt;If you have ever used the built-in sqlite3 module in a multithreaded Python application, you may have seen this message.&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 4316169600 and this is thread id 6190804992.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code can be used to reproduce the error:&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;from&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;threading&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt; &lt;span style="color: #000"&gt;Thread&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;sqlite3&lt;/span&gt;

&lt;span style="color: #000"&gt;conn&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;sqlite3&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;connect&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;:memory:&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;


&lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;f&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;():&lt;/span&gt;
    &lt;span style="color: #000"&gt;conn&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;select 1&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;fetchall&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt;


&lt;span style="color: #000"&gt;Thread&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;target&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #000"&gt;f&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;start&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="the-python-docs"&gt;The Python docs&lt;/h2&gt;
&lt;p&gt;After seeing those errors, I checked the Python docs. The &lt;a href="https://docs.python.org/3/library/sqlite3.html#sqlite3.connect"&gt;sqlite3.connect&lt;/a&gt; method accepts a &lt;code&gt;check_same_thread&lt;/code&gt; parameter, which can be set to &lt;code&gt;False&lt;/code&gt; and the error will disappear.&lt;/p&gt;</content></entry><entry><title>The best code is easy code</title><link href="https://ricardoanderegg.com/posts/easy-code-is-best-code/" /><id>https://ricardoanderegg.com/posts/easy-code-is-best-code/</id><published>2021-07-23T00:00:00+00:00</published><updated>2021-07-23T00:00:00+00:00</updated><content type="html">&lt;p&gt;The best code is the one that is easy to understand.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;&lt;img alt="" src="/img/s/code_style_years.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://twitter.com/LeaVerou/status/1306001020636540934"&gt;Source&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;People don&amp;rsquo;t focus on code readability. Readability is like writing documentation. It takes extra time, more key presses, and you need to stick to it to make it work in the long term. However, sometimes people write code like this:&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #000"&gt;settings&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000; font-weight: bold"&gt;{&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #0000CF; font-weight: bold"&gt;1&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #0000CF; font-weight: bold"&gt;2&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;baz&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt; &lt;span style="color: #0000CF; font-weight: bold"&gt;3&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;}&lt;/span&gt;

&lt;span style="color: #000"&gt;results&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000; font-weight: bold"&gt;[&lt;/span&gt;&lt;span style="color: #000"&gt;parse_document&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;settings&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;r&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)[&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;somekey&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;]&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;get&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;foobar&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt; &lt;span style="color: #204A87; font-weight: bold"&gt;for&lt;/span&gt; &lt;span style="color: #000"&gt;r&lt;/span&gt; &lt;span style="color: #204A87; font-weight: bold"&gt;in&lt;/span&gt; &lt;span style="color: #000"&gt;get_documents&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code is understandable, but I need to guess:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I suppose &lt;code&gt;parse_document()&lt;/code&gt; is returning some kind of dictionary&lt;/li&gt;
&lt;li&gt;There&amp;rsquo;s another indexing operation. The dictionary is probably nested.&lt;/li&gt;
&lt;li&gt;What is &lt;code&gt;r&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Is &lt;code&gt;parse_document()&lt;/code&gt; mutating &lt;code&gt;settings&lt;/code&gt;? Can &lt;code&gt;settings&lt;/code&gt; have other keys?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you find a situation like this, the solution is usually going inside the functions and reading the code, which may be tedious. Yes, maybe you are avoiding creating a couple of variables, but at what cost?&lt;/p&gt;</content></entry><entry><title>Heroku-style deployments with Docker and git tags</title><link href="https://ricardoanderegg.com/posts/git-push-deployments-docker-tags/" /><id>https://ricardoanderegg.com/posts/git-push-deployments-docker-tags/</id><published>2021-04-25T00:00:00+00:00</published><updated>2021-04-25T00:00:00+00:00</updated><content type="html">&lt;p&gt;In this post I want to explain a new deployment method I came up with while working on &lt;a href="https://drwn.io"&gt;drwn.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I wanted it to meet a few requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Simple&lt;/li&gt;
&lt;li&gt;Based on git tags&lt;/li&gt;
&lt;li&gt;Zero-downtime&lt;/li&gt;
&lt;li&gt;Easy rollbacks&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="creating-an-empty-remote-in-the-server"&gt;Creating an empty remote in the server&lt;/h2&gt;
&lt;p&gt;Imagine you already have your project with some code that is being synchronized with a git service like GitHub. To have a &lt;code&gt;git push&lt;/code&gt; based deployment, we need to have our own remote. We will push our code to that remote the same way we do to GitHub.&lt;/p&gt;</content></entry><entry><title>Bloom filters explained in an image</title><link href="https://ricardoanderegg.com/posts/bloom-filters-poster/" /><id>https://ricardoanderegg.com/posts/bloom-filters-poster/</id><published>2021-04-11T00:00:00+00:00</published><updated>2021-04-11T00:00:00+00:00</updated><content type="html">&lt;p&gt;A Bloom filter is a probabilistic data structure present in many common applications. Its purpose is answering the question: &amp;ldquo;is this item in the set?&amp;rdquo; very fast and not using a lot of space. The answers can be NO, or MAYBE YES. They work using hash functions, &lt;a href="https://ricardoanderegg.com/posts/what-is-a-hash-function-different-types/"&gt;we learned about them&lt;/a&gt; some time ago.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/img/s/bloom-filters-poster.png"&gt;&lt;/p&gt;
&lt;p&gt;For example, one use case of Bloom filters is the following: you have a huge
list of malicious URLs. In your browser, before a user navigates to a new URL, you want to check if it&amp;rsquo;s inside the list of dangerous URLs. You can use a bloom filter to do that! It will take less space than saving the full list of URLs, and if the answer from the Bloom filter is &amp;ldquo;no&amp;rdquo; (the URL is not a malicious one), you can safely let the user visit it. If you want to learn how to implement a Bloom filter from scratch, you can do it &lt;a href="https://ricardoanderegg.com/posts/understanding-bloom-filters-by-building-one/"&gt;here&lt;/a&gt;. And if you liked this post, feel free to share it and tag me!&lt;/p&gt;</content></entry><entry><title>Understanding Bloom Filters by building one</title><link href="https://ricardoanderegg.com/posts/understanding-bloom-filters-by-building-one/" /><id>https://ricardoanderegg.com/posts/understanding-bloom-filters-by-building-one/</id><published>2021-04-06T00:00:00+00:00</published><updated>2021-04-06T00:00:00+00:00</updated><content type="html">&lt;h2 id="what-is-a-bloom-filter"&gt;What is a Bloom Filter?&lt;/h2&gt;
&lt;p&gt;A Bloom filter is a probabilistic data structure. It tells you if an element is in a set or not in a very fast and memory-efficient way. A Bloom filter can tell if an element &lt;strong&gt;is not in&lt;/strong&gt; the set (&amp;ldquo;being 100% sure&amp;rdquo;) or that &lt;strong&gt;it may be in&lt;/strong&gt; the set, but not &amp;ldquo;being 100% sure&amp;rdquo;. It only has 2 operations: &lt;code&gt;add&lt;/code&gt;, to add an element, and &lt;code&gt;query&lt;/code&gt;, to check if an element exists in the set or not.&lt;/p&gt;</content></entry><entry><title>Hash functions explained in an image</title><link href="https://ricardoanderegg.com/posts/what-is-a-hash-function-different-types/" /><id>https://ricardoanderegg.com/posts/what-is-a-hash-function-different-types/</id><published>2021-03-11T00:00:00+00:00</published><updated>2021-03-11T00:00:00+00:00</updated><content type="html">&lt;p&gt;Hash functions are a fundamental part of modern programming. They map a variable-sized input to a fixed-size output.&lt;/p&gt;
&lt;p&gt;We can use them to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify the integrity of files and make sure they have not been modified.&lt;/li&gt;
&lt;li&gt;Save a password in a database without the risk that if somebody steals the data, they will be able to know the passwords.&lt;/li&gt;
&lt;li&gt;Create a hash table to store items. With that, we can find them faster and using less memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="/img/s/hash-functions-poster.png"&gt;&lt;/p&gt;</content></entry><entry><title>Multiple, shared, in-memory SQLite databases in Python</title><link href="https://ricardoanderegg.com/posts/python-multiple-shared-in-memory-sqlite-databases/" /><id>https://ricardoanderegg.com/posts/python-multiple-shared-in-memory-sqlite-databases/</id><published>2021-02-16T00:00:00+00:00</published><updated>2021-02-16T00:00:00+00:00</updated><content type="html">&lt;p&gt;This works only in the same Python process, you can&amp;rsquo;t share an in-memory SQLite database between processes in this way.&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;sqlite3&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# NOTE: you need to use uri=True&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# 3 connections to the same in-memory database (DB1 / memdb1)&lt;/span&gt;
&lt;span style="color: #000"&gt;DB1_1&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;sqlite3&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;connect&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;file:memdb1?mode=memory&amp;amp;cache=shared&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;uri&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;True&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
&lt;span style="color: #000"&gt;DB1_2&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;sqlite3&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;connect&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;file:memdb1?mode=memory&amp;amp;cache=shared&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;uri&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;True&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
&lt;span style="color: #000"&gt;DB1_3&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;sqlite3&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;connect&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;file:memdb1?mode=memory&amp;amp;cache=shared&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;uri&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;True&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# 2 connections to a *new* in-memory database (DB2 / memdb2)&lt;/span&gt;
&lt;span style="color: #000"&gt;DB2_1&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;sqlite3&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;connect&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;file:memdb2?mode=memory&amp;amp;cache=shared&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;uri&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;True&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
&lt;span style="color: #000"&gt;DB2_2&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;sqlite3&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;connect&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;file:memdb2?mode=memory&amp;amp;cache=shared&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000"&gt;uri&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;True&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# create a table in both DBs&lt;/span&gt;
&lt;span style="color: #8F5902; font-style: italic"&gt;# DB1&lt;/span&gt;
&lt;span style="color: #000"&gt;DB1_1&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;create table if not exists dict(key text, value text)&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# DB2&lt;/span&gt;
&lt;span style="color: #000"&gt;DB2_1&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;create table if not exists dict(key text, value text)&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# insert some values in both DBs with *one* of the connections&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;with&lt;/span&gt; &lt;span style="color: #000"&gt;DB1_1&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt;
    &lt;span style="color: #000"&gt;DB1_1&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;insert into dict values (&amp;#39;asdas&amp;#39;, &amp;#39;foobar&amp;#39;)&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

&lt;span style="color: #204A87; font-weight: bold"&gt;with&lt;/span&gt; &lt;span style="color: #000"&gt;DB2_1&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt;
    &lt;span style="color: #000"&gt;DB2_1&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;insert into dict values (&amp;#39;barasd&amp;#39;, &amp;#39;barfoo&amp;#39;)&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# check that all the connections for a database have the same data&lt;/span&gt;
&lt;span style="color: #8F5902; font-style: italic"&gt;# DB1&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;assert&lt;/span&gt; &lt;span style="color: #000"&gt;DB1_1&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;select * from dict&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;fetchall&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;==&lt;/span&gt; &lt;span style="color: #000; font-weight: bold"&gt;[(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;asdas&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;foobar&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)]&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;assert&lt;/span&gt; &lt;span style="color: #000"&gt;DB1_2&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;select * from dict&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;fetchall&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;==&lt;/span&gt; &lt;span style="color: #000; font-weight: bold"&gt;[(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;asdas&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;foobar&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)]&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;assert&lt;/span&gt; &lt;span style="color: #000"&gt;DB1_3&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;select * from dict&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;fetchall&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;==&lt;/span&gt; &lt;span style="color: #000; font-weight: bold"&gt;[(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;asdas&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;foobar&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)]&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# DB2&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;assert&lt;/span&gt; &lt;span style="color: #000"&gt;DB2_1&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;select * from dict&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;fetchall&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;==&lt;/span&gt; &lt;span style="color: #000; font-weight: bold"&gt;[(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;barasd&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;barfoo&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)]&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;assert&lt;/span&gt; &lt;span style="color: #000"&gt;DB2_2&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;execute&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;select * from dict&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;fetchall&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;()&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;==&lt;/span&gt; &lt;span style="color: #000; font-weight: bold"&gt;[(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;barasd&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;barfoo&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content></entry><entry><title>Vanishing feedback button with FastAPI and hyperscript</title><link href="https://ricardoanderegg.com/posts/easy-feedback-button-fastapi-htmx-javascript-hyperscript/" /><id>https://ricardoanderegg.com/posts/easy-feedback-button-fastapi-htmx-javascript-hyperscript/</id><published>2021-02-11T00:00:00+00:00</published><updated>2021-02-11T00:00:00+00:00</updated><content type="html">&lt;p&gt;Feedback is one of the most importante things when you are creating a product (probably the most important one!), so it should be easy for users to give feedback. In this post we&amp;rsquo;ll see how to implement a feedback button easily. This exact code is what I&amp;rsquo;m using at &lt;a href="https://drwn.io/"&gt;drwn.io&lt;/a&gt;, a little project I&amp;rsquo;m working on with a friend.&lt;/p&gt;
&lt;p&gt;The button does the following: after you use it, it will change its text to &amp;ldquo;Thank you!&amp;rdquo;, then it will fade out we will have our backend handle the message. Let&amp;rsquo;s see it in action:
&lt;img alt="" src="/img/s/feedbackbtn.gif"&gt;&lt;/p&gt;</content></entry><entry><title>Managing Python environments with mamba and pip-tools</title><link href="https://ricardoanderegg.com/posts/python-manage-environments-with-mamba-pip-tools/" /><id>https://ricardoanderegg.com/posts/python-manage-environments-with-mamba-pip-tools/</id><published>2021-01-25T00:00:00+00:00</published><updated>2021-01-25T00:00:00+00:00</updated><content type="html">&lt;p&gt;Some time ago I published &lt;a href="https://ricardoanderegg.com/posts/conda_management/"&gt;a post&lt;/a&gt; about managing Conda environments. My workflow has changed quite a bit since then, and I&amp;rsquo;ve moved to &lt;a href="https://docs.python.org/3/tutorial/venv.html"&gt;venv&lt;/a&gt; + &lt;a href="https://github.com/jazzband/pip-tools"&gt;pip-tools&lt;/a&gt;, but I&amp;rsquo;ll leave that for another post. Today I want to talk about new experiments I&amp;rsquo;m making with &lt;a href="https://github.com/mamba-org/mamba"&gt;mamba&lt;/a&gt; + &lt;a href="https://github.com/jazzband/pip-tools"&gt;pip-tools&lt;/a&gt;. If you don&amp;rsquo;t know about mamba, it&amp;rsquo;s kind of a &lt;a href="https://docs.conda.io/en/latest/miniconda.html"&gt;miniconda&lt;/a&gt; replacement. It just works a lot better, and it&amp;rsquo;s VERY fast.&lt;/p&gt;
&lt;p&gt;Triggered by &lt;a href="https://twitter.com/full_stack_dl/status/1346606996011642883"&gt;this tweet&lt;/a&gt;, I feel like writing about this new experimental workflow. We will see how it works, some problems that may come up and workarounds to fix them.&lt;/p&gt;</content></entry><entry><title>Single file applications</title><link href="https://ricardoanderegg.com/posts/write-apps-in-single-file/" /><id>https://ricardoanderegg.com/posts/write-apps-in-single-file/</id><published>2020-11-03T00:00:00+00:00</published><updated>2020-11-03T00:00:00+00:00</updated><content type="html">&lt;p&gt;Storytelling is part of the human essence. Stories have let humans survive until today, they became the medium to move information between individuals.&lt;/p&gt;
&lt;p&gt;Programming can be considered another form of moving information. With different levels of abstraction, programming becomes a medium to transfer information between humans and computers.&lt;/p&gt;
&lt;p&gt;A programming paradigm mixing those two concepts is &lt;strong&gt;literate programming&lt;/strong&gt;. According to its definition:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Literate programming is a methodology that combines a programming language with a documentation language, thereby making programs more robust, more portable, more easily maintained, and arguably more fun to write than programs that are written only in a high-level language. The main idea is to treat a program as a piece of literature, addressed to human beings rather than to a computer.&lt;/em&gt; &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;</content></entry><entry><title>Notes on Simple Made Easy</title><link href="https://ricardoanderegg.com/posts/notes-simple-made-easy-rich-hickey/" /><id>https://ricardoanderegg.com/posts/notes-simple-made-easy-rich-hickey/</id><published>2020-09-22T00:00:00+00:00</published><updated>2020-09-22T00:00:00+00:00</updated><content type="html">&lt;p&gt;These are my notes on the talks &lt;a href="https://www.youtube.com/watch?v=kGlVcSMgtV4"&gt;&amp;ldquo;Simple Made Easy&amp;rdquo; by Rich Hickey&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Simplicity is a prerequisite for reliability&lt;/em&gt; - Dijkstra&lt;/p&gt;
&lt;p&gt;Simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One role.&lt;/li&gt;
&lt;li&gt;One task.&lt;/li&gt;
&lt;li&gt;One concept.&lt;/li&gt;
&lt;li&gt;One dimension.&lt;/li&gt;
&lt;li&gt;Lack of interleaving. (Does not mean there&amp;rsquo;s only one thing)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Easy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Near&amp;rdquo;. To our understanding, skill/set or capabilities.&lt;/li&gt;
&lt;li&gt;Easy is relative.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can only make reliable those things we can understand.&lt;/p&gt;
&lt;p&gt;We can only consider a few things at a time. If a piece is intertwined with another we already have to keep both in mind. It&amp;rsquo;s combinatorial.&lt;/p&gt;</content></entry><entry><title>Short posts</title><link href="https://ricardoanderegg.com/posts/write-short-blog-posts/" /><id>https://ricardoanderegg.com/posts/write-short-blog-posts/</id><published>2020-07-31T00:00:00+00:00</published><updated>2020-07-31T00:00:00+00:00</updated><content type="html">&lt;p&gt;Our attention spans are short. Even more when looking for new information. We get flooded by different sources. Most of them contain little useful information. Content should be concise, packed with information and clean of empty prose. Focused around examples. Remove everything not related to the title.&lt;/p&gt;
&lt;p&gt;When was the last time you spent more than 15 minutes reading a single piece of information?&lt;/p&gt;
&lt;p&gt;That is why I started writing &lt;a href="https://ricardoanderegg.com/recipes/"&gt;recipes&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>Connect to remote docker host via SSH.</title><link href="https://ricardoanderegg.com/posts/remote-manage-docker-with-ssh/" /><id>https://ricardoanderegg.com/posts/remote-manage-docker-with-ssh/</id><published>2020-07-29T00:00:00+00:00</published><updated>2020-07-29T00:00:00+00:00</updated><content type="html">&lt;p&gt;I could not get reliable connections with docker-machine or docker context. This is how I got 100% reliable connections through ssh forwarding.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also more secure. You don&amp;rsquo;t need to expose any additional ports.&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# create bash function&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;function&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;dockcon&lt;span style="color: #CE5C00; font-weight: bold"&gt;()&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;{&lt;/span&gt;

&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# if used with the argument `unset`, close the connection&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# see the part after this conditional to understand it better&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;if&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;[[&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000"&gt;$1&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;==&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;unset&amp;quot;&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;]]&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;;&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;then&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;        &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# get the PID of the ssh process and kill it&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;        &lt;/span&gt;&lt;span style="color: #204A87"&gt;kill&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;$(&lt;/span&gt;cat&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;docker_connection.pid&lt;span style="color: #204A87; font-weight: bold"&gt;)&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;&lt;/span&gt;

&lt;span style="color: #F8F8F8"&gt;        &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# unset the environment variable&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;        &lt;/span&gt;&lt;span style="color: #204A87"&gt;unset&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;DOCKER_HOST

&lt;span style="color: #F8F8F8"&gt;        &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# remove the file with the PID&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;        &lt;/span&gt;rm&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;docker_connection.pid

&lt;span style="color: #F8F8F8"&gt;        &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# end&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;        &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;return&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;fi&lt;/span&gt;


&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# generate a random integer between 27000 and 37000 to choose as a port&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #000"&gt;PORT&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;$((&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;RANDOM&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;%&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold"&gt;10000&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;)&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt;  &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;+&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold"&gt;27000&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;))&lt;/span&gt;

&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# connect via ssh&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# forward the remote docker socket to a local port on your machine&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# the argument &amp;quot;$1&amp;quot; is the remote host&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# echo the PID of the ssh connection to a text file&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;ssh&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;-NL&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;localhost:&lt;span style="color: #000"&gt;$PORT&lt;/span&gt;:/var/run/docker.sock&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000"&gt;$1&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #204A87"&gt;echo&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;$!&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&amp;gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;docker_connection.pid

&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# set the environment variable to tell docker which host to use&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;&lt;span style="color: #204A87"&gt;export&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;DOCKER_HOST&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;tcp://localhost:&lt;/span&gt;&lt;span style="color: #000"&gt;$PORT&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;&lt;/span&gt;
&lt;span style="color: #CE5C00; font-weight: bold"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Usage:&lt;/p&gt;</content></entry><entry><title>Run your containers as non-root</title><link href="https://ricardoanderegg.com/posts/local-files-permissions-docker-non-root-security/" /><id>https://ricardoanderegg.com/posts/local-files-permissions-docker-non-root-security/</id><published>2020-07-22T00:00:00+00:00</published><updated>2020-07-22T00:00:00+00:00</updated><content type="html">&lt;p&gt;Docker runs as root. The programs executing inside containers too. Make it a bit better.&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;# do everything you need as root (maybe installing some dependencies)&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# create a non-root user&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;RUN&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;addgroup&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;--gid&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold"&gt;1001&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;appgroup
&lt;span style="color: #204A87; font-weight: bold"&gt;RUN&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;useradd&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;--create-home&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;--gid&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold"&gt;1001&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;--uid&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold"&gt;1001&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;appuser

&lt;span style="color: #8F5902; font-style: italic"&gt;# set new workdir&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;WORKDIR&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;/home/appuser&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# activate non-root user&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;USER&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;appuser&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic"&gt;# copy new files with correct permissions&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;COPY&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;--chown&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;appuser:appgroup&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;app.py&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you need to mount or use files from your file system, give permissions to the UID/GID defined above:&lt;/p&gt;</content></entry><entry><title>Put your bash code in functions</title><link href="https://ricardoanderegg.com/posts/wrap-bash-code-functions/" /><id>https://ricardoanderegg.com/posts/wrap-bash-code-functions/</id><published>2020-06-16T00:00:00+00:00</published><updated>2020-06-16T00:00:00+00:00</updated><content type="html">&lt;p&gt;I wrote my degree dissertation in jupyter notebooks. Then I converted them to markdown and finally to pdf with pandoc. I also had to output an office file so that my tutor could work on it too. The initial code was:&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #8F5902; font-style: italic"&gt;#!/usr/bin/env bash&lt;/span&gt;


&lt;span style="color: #000"&gt;ProcessName&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;PDF Expert&amp;quot;&lt;/span&gt;
&lt;span style="color: #000"&gt;number&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;$(&lt;/span&gt;ps&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;aux&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;|&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;grep&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;-v&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;grep&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;|&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;grep&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;-ci&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000"&gt;$ProcessName&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;)&lt;/span&gt;
&lt;span style="color: #8F5902; font-style: italic"&gt;# echo $number&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;if&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;[&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000"&gt;$number&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;-le&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold"&gt;0&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;]&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;then&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;open&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;-a&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;#39;PDF Expert&amp;#39;&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold"&gt;fi&lt;/span&gt;
pandoc&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;final.md&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;format.yaml&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--filter&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;pandoc-citeproc&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--table-of-contents&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--number-sections&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--pdf-engine&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;xelatex&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--indented-code-classes&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;python&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--highlight-style&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;pygments&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--template&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;./eisvogel2.tex&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--listings&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;-o&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;final.pdf
pandoc&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;final.md&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;format.yaml&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--filter&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;pandoc-citeproc&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--table-of-contents&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--number-sections&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--indented-code-classes&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;python&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--highlight-style&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;pygments&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;--template&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;./eisvogel.tex&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;-V&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;lang&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt;es&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8"&gt;    &lt;/span&gt;-o&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;final.docx

open&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;final.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code does the following:&lt;/p&gt;</content></entry><entry><title>Conda management</title><link href="https://ricardoanderegg.com/posts/python-manage-conda-environments/" /><id>https://ricardoanderegg.com/posts/python-manage-conda-environments/</id><published>2020-02-21T00:00:00+00:00</published><updated>2020-02-21T00:00:00+00:00</updated><content type="html">&lt;p&gt;Manage conda environments and Jupyterlab easily.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Use &lt;a href="https://github.com/polyrand/scripts/blob/master/condacreate_dev.sh"&gt;this&lt;/a&gt; script to create a base conda environment with Jupyterlab and some plugins, and &lt;a href="https://github.com/polyrand/scripts/blob/master/condacreate.sh"&gt;this&lt;/a&gt; to create new environments and make them available when launching Jupyter.&lt;/p&gt;
&lt;p&gt;Managing environments in Python can be tricky. I used to have a default script to create a conda environment, in that script I would install all the packages I consider basic, plus Jupyterlab and some plugins. Yes a new fresh Jupyterlab+plugins for every environment.&lt;/p&gt;</content></entry><entry><title>Education before innovation</title><link href="https://ricardoanderegg.com/posts/education-before-innovation/" /><id>https://ricardoanderegg.com/posts/education-before-innovation/</id><published>2020-02-07T00:00:00+00:00</published><updated>2020-02-07T00:00:00+00:00</updated><content type="html">&lt;p&gt;We live in a fast changing world, everyone seems to be working on the next big thing while you still haven&amp;rsquo;t got used to the previous big thing. We look at technology, science and innovation as our new saving god, while overlooking something more fundamental: education.&lt;/p&gt;
&lt;p&gt;It seems we just want to solve everything with technology and new discoveries: travelling, diseases, waiting times to visit a doctor, etc. I believe many of those things could be alleviated with a better education instead of throwing money and headlines at the next company trying to solve it.&lt;/p&gt;</content></entry><entry><title>Fixing a bug in the Haskell installer</title><link href="https://ricardoanderegg.com/posts/fixing-ghcup-bug/" /><id>https://ricardoanderegg.com/posts/fixing-ghcup-bug/</id><published>2020-01-16T00:00:00+00:00</published><updated>2020-01-16T00:00:00+00:00</updated><content type="html">&lt;p&gt;The story of a bug fix. I found a bug in the default Haskell installer &lt;a href="https://gitlab.haskell.org/haskell/ghcup"&gt;ghcup&lt;/a&gt;, fixed it in my computer and had the fix merged to the public installer.&lt;/p&gt;
&lt;p&gt;I started doing the MIT course &lt;a href="http://brendanfong.com/programmingcats.html"&gt;Programming with Categories&lt;/a&gt;, so I had to install Haskell on my computer. But following the recommended method kept throwing me an error: &lt;code&gt;mktemp: too few X's in template ‘ghcup’&lt;/code&gt;. After some time searching I could only find 1 discussion where someone had had a similar problem.&lt;/p&gt;</content></entry><entry><title>Divide, Search, Abstract</title><link href="https://ricardoanderegg.com/posts/problem-solving-divide-search-abstract/" /><id>https://ricardoanderegg.com/posts/problem-solving-divide-search-abstract/</id><published>2019-11-28T00:00:00+00:00</published><updated>2019-11-28T00:00:00+00:00</updated><content type="html">&lt;p&gt;Some problems are harder than others, but having a system to approach them makes a big difference.&lt;/p&gt;
&lt;p&gt;Yesterday I finished teaching my first Python course. Apart from teaching about generators, decorators, coroutines, multiprocessing, pandas, flask, pytest, docker&amp;hellip; and a long list of development tools and Python modules, I tried to transmit an important message I believe is a lot more fundamental than knowing all the technicalities, and it is problem solving.&lt;/p&gt;</content></entry><entry><title>Language identification with fastText</title><link href="https://ricardoanderegg.com/posts/python-fast-language-identification-fasttext/" /><id>https://ricardoanderegg.com/posts/python-fast-language-identification-fasttext/</id><published>2019-08-20T00:00:00+00:00</published><updated>2019-08-20T00:00:00+00:00</updated><content type="html">&lt;p&gt;When dealing with a multilingual dataset doing language identification is a very important part of the analysis process, here I&amp;rsquo;ll show a way to do a fast ⚡️ and reliable ✨ language identification with &lt;a href="https://fasttext.cc"&gt;fasttext&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;lt;TL;DR&amp;gt;&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;wget&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight" style="background: #f8f8f8"&gt;&lt;pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none; line-height: 125%;"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #204A87; font-weight: bold"&gt;import&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;fasttext&lt;/span&gt;

&lt;span style="color: #000"&gt;lid_model&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;fasttext&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;load_model&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;#39;lid.176.bin&amp;#39;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;

&lt;span style="color: #204A87; font-weight: bold"&gt;def&lt;/span&gt;&lt;span style="color: #F8F8F8"&gt; &lt;/span&gt;&lt;span style="color: #000"&gt;detector&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;text&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;):&lt;/span&gt;
    &lt;span style="color: #8F5902; font-style: italic"&gt;# return empty string if there is no tweet&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;if&lt;/span&gt; &lt;span style="color: #000"&gt;text&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;isspace&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;():&lt;/span&gt;
        &lt;span style="color: #204A87; font-weight: bold"&gt;return&lt;/span&gt; &lt;span style="color: #4E9A06"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span style="color: #204A87; font-weight: bold"&gt;else&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;:&lt;/span&gt;
        &lt;span style="color: #8F5902; font-style: italic"&gt;# get first item of the prediction tuple, then split by &amp;quot;__label__&amp;quot; and return only language code&lt;/span&gt;
        &lt;span style="color: #204A87; font-weight: bold"&gt;return&lt;/span&gt; &lt;span style="color: #000"&gt;lid_model&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;predict&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;text&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)[&lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold"&gt;0&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;][&lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold"&gt;0&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;]&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;split&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;quot;__label__&amp;quot;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)[&lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold"&gt;1&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;]&lt;/span&gt;

&lt;span style="color: #000"&gt;df&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;[&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;#39;language&amp;#39;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;]&lt;/span&gt; &lt;span style="color: #CE5C00; font-weight: bold"&gt;=&lt;/span&gt; &lt;span style="color: #000"&gt;df&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;[&lt;/span&gt;&lt;span style="color: #4E9A06"&gt;&amp;#39;Tweet&amp;#39;&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;]&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold"&gt;.&lt;/span&gt;&lt;span style="color: #000"&gt;apply&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000"&gt;detector&lt;/span&gt;&lt;span style="color: #000; font-weight: bold"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&amp;lt;/TL;DR&amp;gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First fo all we need to download a dataset to play with. We&amp;rsquo;ll use the &lt;a href="https://github.com/Kaggle/kaggle-api"&gt;kaggle CLI tool&lt;/a&gt;. Run the following command after installing it or download the dataset &lt;a href="https://www.kaggle.com/rtatman/the-umass-global-english-on-twitter-dataset"&gt;directly from kaggle&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>Linking notebooks</title><link href="https://ricardoanderegg.com/posts/python-jupyter-link-local-notebook/" /><id>https://ricardoanderegg.com/posts/python-jupyter-link-local-notebook/</id><published>2019-07-25T00:00:00+00:00</published><updated>2019-07-25T00:00:00+00:00</updated><content type="html">&lt;p&gt;There is a little trick I just found about, which I think can be very useful when you split tasks across different notebooks.&lt;/p&gt;
&lt;p&gt;Jupyter notebooks keep gaining popularity and use cases, the rapid growth of the tooling ecosystem around it is just one proof (for example &lt;a href="https://github.com/QuantStack/voila"&gt;voilà&lt;/a&gt; or &lt;a href="https://panel.pyviz.org/"&gt;panel&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Most people choose Jupyter when publishing a course or tutorial on Github and that&amp;rsquo;s great, but when there are a lot of notebooks it can become messy.&lt;/p&gt;</content></entry><entry><title>Formatting jupyter notebooks with black</title><link href="https://ricardoanderegg.com/posts/black-formatting-jupyter-notebook/" /><id>https://ricardoanderegg.com/posts/black-formatting-jupyter-notebook/</id><published>2019-07-22T00:00:00+00:00</published><updated>2019-07-22T00:00:00+00:00</updated><content type="html">&lt;p&gt;After nearly a year coding in Python (although not consistently), I started trying code formatters and discovered they were more useful than I thought. Here are some reason why.&lt;/p&gt;
&lt;p&gt;First, I must admit these tips may be biased by the fact I use &lt;a href="https://jupyterlab.readthedocs.io/en/stable/"&gt;Jupyter Notebooks&lt;/a&gt; quite a lot. I think they are an incredible tool for learning although they may also instill some bad coding habits.&lt;/p&gt;
&lt;p&gt;Before talking about &lt;a href="https://github.com/psf/black"&gt;black&lt;/a&gt; lets go through the step to install it and use it with Jupyter Notebooks.&lt;/p&gt;</content></entry><entry><title>About me</title><link href="https://ricardoanderegg.com/about/" /><id>https://ricardoanderegg.com/about/</id><published>2019-06-01T00:00:00+00:00</published><updated>2019-06-01T00:00:00+00:00</updated><content type="html">&lt;p&gt;My name is Ricardo Ander-Egg Aguilar. I am a medical doctor working as a sofware
engineer and machine learning developer. I currently live in Barcelona.&lt;/p&gt;
&lt;p&gt;I really love programming, maths, statistics and thinking about how current
problems can be solved.&lt;/p&gt;
&lt;p&gt;Regarding my other interests, I have been a swimmer for 20 years, sport is just
a part of me. I love hiking and travelling, I am also a salsa dancer.&lt;/p&gt;</content></entry></feed>