<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Ashley Connor&apos;s TIL</title><description>Short notes on things I&apos;ve learned.</description><link>https://til.ashleyconnor.co.uk/</link><item><title>Installing ssh-copy-id on a Synology NAS</title><link>https://til.ashleyconnor.co.uk/2026-10-29-installing-ssh-copy-id-on-a-synology-nas/</link><guid isPermaLink="true">https://til.ashleyconnor.co.uk/2026-10-29-installing-ssh-copy-id-on-a-synology-nas/</guid><pubDate>Thu, 29 Oct 2026 17:20:21 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code&gt;ssh-copy-id&lt;/code&gt; isn’t installed on DSM 7+ and is unavailable from the Synology Package Center (or the &lt;a href=&quot;https://synocommunity.com/&quot;&gt;SynoCommunity Package repo&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I wanted to copy SSH keys between my DS420+ and my other servers so let’s install the tool to do that.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://til.ashleyconnor.co.uk/_astro/ec.787mv.css&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-p&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;/.local/bin&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;/.ssh&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;700&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;/.ssh&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-fL&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;https://raw.githubusercontent.com/openssh/openssh-portable/master/contrib/ssh-copy-id&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-o&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;/.local/bin/ssh-copy-id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;755&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;/.local/bin/ssh-copy-id&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;mkdir -p &amp;quot;$HOME/.local/bin&amp;quot; &amp;quot;$HOME/.ssh&amp;quot;chmod 700 &amp;quot;$HOME/.ssh&amp;quot;curl -fL \  https://raw.githubusercontent.com/openssh/openssh-portable/master/contrib/ssh-copy-id \  -o &amp;quot;$HOME/.local/bin/ssh-copy-id&amp;quot; &amp;amp;&amp;amp;chmod 755 &amp;quot;$HOME/.local/bin/ssh-copy-id&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Validate the installation and add to the PATH&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;/.local/bin/ssh-copy-id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-h&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#919AA3&quot;&gt;# make the command available on the PATH in the current session&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; PATH&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;/.local/bin:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;$PATH&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#919AA3&quot;&gt;# [optional] persist it across new sessions&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;export PATH=&quot;$HOME/.local/bin:$PATH&quot;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;~/.profile&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&amp;quot;$HOME/.local/bin/ssh-copy-id&amp;quot; -hexport PATH=&amp;quot;$HOME/.local/bin:$PATH&amp;quot;echo &amp;#x27;export PATH=&amp;quot;$HOME/.local/bin:$PATH&amp;quot;&amp;#x27; &gt; ~/.profile&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Finally we can call it with the key we wish to copy&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;ssh-copy-id&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-i&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;/.ssh/id_ed25519.pub&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;username@destination&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;ssh-copy-id -i &amp;quot;$HOME/.ssh/id_ed25519.pub&amp;quot; username@destination&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you don’t have a key yet, generate one using &lt;code&gt;ssh-keygen&lt;/code&gt; which is installed on DSM 7+&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;ssh-keygen&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-t&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;ed25519&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;ssh-keygen -t ed25519&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;I also add an SSH conf entry to make it easier to connect to each server&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e6edf3&quot;&gt;Host desktop&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#e6edf3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#e6edf3&quot;&gt;HostName &amp;lt;ip_address&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#e6edf3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#e6edf3&quot;&gt;User &amp;lt;user&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#e6edf3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#e6edf3&quot;&gt;IdentityFile /var/services/homes/&amp;lt;user&amp;gt;/.ssh/id_ed25519&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#e6edf3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#e6edf3&quot;&gt;IdentitiesOnly yes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Host desktop    HostName &lt;ip_address&gt;    User &lt;user&gt;    IdentityFile /var/services/homes/&lt;user&gt;/.ssh/id_ed25519    IdentitiesOnly yes&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then we can simply call &lt;code&gt;ssh desktop&lt;/code&gt; to connect.&lt;/p&gt;
</content:encoded><category>tools</category><category>synology</category></item><item><title>Automatically Activating a Virtual Environment with direnv</title><link>https://til.ashleyconnor.co.uk/2025-03-01-how-to-automatically-activate-venv-with-direnv/</link><guid isPermaLink="true">https://til.ashleyconnor.co.uk/2025-03-01-how-to-automatically-activate-venv-with-direnv/</guid><pubDate>Sat, 01 Mar 2025 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When working with Python projects, activating a virtual environment (&lt;a href=&quot;https://docs.python.org/3/library/venv.html&quot;&gt;venv&lt;/a&gt;) manually every time you switch to a project directory can be tedious. Fortunately, &lt;a href=&quot;https://direnv.net/&quot;&gt;direnv&lt;/a&gt; provides a way to automate this process.&lt;/p&gt;
&lt;h2 id=&quot;automatically-activating-a-virtual-environment&quot;&gt;Automatically Activating a Virtual Environment&lt;/h2&gt;
&lt;p&gt;When navigating to a project’s root directory, you likely want the associated virtual environment to activate automatically. A common approach is using direnv with a &lt;code&gt;.envrc&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://til.ashleyconnor.co.uk/_astro/ec.787mv.css&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.venv/bin/activate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;source .venv/bin/activate&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With this setup, direnv loads the virtual environment when you enter the directory and unloads it when you leave:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;❯&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;blog/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;direnv:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;loading&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;~/Projects/blog/.envrc&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;direnv:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;+VIRTUAL_ENV&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;+VIRTUAL_ENV_PROMPT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;~PATH&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;❯&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;..&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;direnv:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;unloading&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;❯ cd blog/direnv: loading ~/Projects/blog/.envrcdirenv: export +VIRTUAL_ENV +VIRTUAL_ENV_PROMPT ~PATH❯ cd ..direnv: unloading&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;an-official-approach&quot;&gt;An Official Approach&lt;/h2&gt;
&lt;p&gt;A better and officially supported method for achieving this in direnv is:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; VIRTUAL_ENV&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;.venv&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;layout&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;python&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;export VIRTUAL_ENV=&amp;quot;.venv&amp;quot;layout python&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This approach leverages direnv’s built-in &lt;code&gt;layout&lt;/code&gt; function which is available for &lt;a href=&quot;https://github.com/direnv/direnv/wiki#project-layouts&quot;&gt;range of programming languages, editors, &amp;amp; tools&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;reusing-the-setup-across-projects&quot;&gt;Reusing the Setup Across Projects&lt;/h2&gt;
&lt;p&gt;For even greater convenience, you can define a custom function to standardize environment activation across all your projects. Check out the &lt;a href=&quot;https://github.com/direnv/direnv/wiki/Python&quot;&gt;direnv wiki&lt;/a&gt; for more details.&lt;/p&gt;
</content:encoded><category>python</category><category>tools</category></item><item><title>How to strip DRM from Audible audiobooks</title><link>https://til.ashleyconnor.co.uk/2022-12-02-how-to-strip-drm-from-audible-audiobooks/</link><guid isPermaLink="true">https://til.ashleyconnor.co.uk/2022-12-02-how-to-strip-drm-from-audible-audiobooks/</guid><pubDate>Fri, 02 Dec 2022 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have a subscription with Audible which allows you to download an audiobook a month for keeps.&lt;/p&gt;
&lt;p&gt;These books can be listened to on the Audible app but if you want to use another app then it needs to support &lt;a href=&quot;https://help.audible.com/s/article/does-audible-use-drm-or-any-other-mechanisms-to-protect-titles-on-audible-from-unauthorized-distribution-and-modification?language=en_US&quot;&gt;Audible’s DRM system&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The particular app I wanted to use did not support DRM so I chose to remove the DRM from my purchases books.&lt;/p&gt;
&lt;p&gt;To do this we’ll use a Python project &lt;code&gt;audible-cli&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Install this using &lt;code&gt;pip&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://til.ashleyconnor.co.uk/_astro/ec.787mv.css&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;pip&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;audible-cli&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ pip install audible-cli&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Once installed we can run &lt;code&gt;audible quickstart&lt;/code&gt; - this will start a wizard that creates a configuration file.&lt;/p&gt;
&lt;p&gt;Next we can run &lt;code&gt;audible library list&lt;/code&gt; to list our Audible library and choose the audiobook we want to download.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;audible&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;library&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;list&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;B015ELUYL4:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;Kurt&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;Vonnegut:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;Slaughterhouse-Five&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ audible library list...B015ELUYL4: Kurt Vonnegut: Slaughterhouse-Five&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We can then download the &lt;code&gt;aax&lt;/code&gt; file using the download subcommand:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;audible&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;download&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;--aax&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;--asin&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;B015ELUYL4&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ audible download --aax --asin B015ELUYL4&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Once downloaded we need the activate bytes to decode the DRM:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;audible&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;activation-bytes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;7224181c&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ audible activation-bytes7224181c&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With these bytes we can convert the &lt;code&gt;aax&lt;/code&gt; to &lt;code&gt;mp3&lt;/code&gt; without DRM:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;ffmpeg&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-activation_bytes&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;7224181c&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-i&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;Slaughterhouse-Five-LC_64_22050_stereo.aax&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;Slaughterhouse-Five-LC_64_22050_stereo.mp3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ ffmpeg -activation_bytes 7224181c -i Slaughterhouse-Five-LC_64_22050_stereo.aax Slaughterhouse-Five-LC_64_22050_stereo.mp3&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Alternatively &lt;a href=&quot;https://github.com/KrumpetPirate/AAXtoMP3&quot;&gt;AAXtoMP3&lt;/a&gt; does a great job of converting the &lt;code&gt;aax&lt;/code&gt; to a variety of codecs (AAC command shown below) whilst keeping metadata and cover-art intact.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;bash&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;AAXtoMP3&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-a&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-A&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;7224181c&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;Slaughterhouse-Five-LC_64_22050_stereo.aax&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ bash AAXtoMP3 -a -A 7224181c Slaughterhouse-Five-LC_64_22050_stereo.aax&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded><category>tools</category><category>python</category></item><item><title>About Elixir Pattern Matching in Anon Functions</title><link>https://til.ashleyconnor.co.uk/2022-12-01-about-elixir-pattern-matching-in-anon-functions/</link><guid isPermaLink="true">https://til.ashleyconnor.co.uk/2022-12-01-about-elixir-pattern-matching-in-anon-functions/</guid><pubDate>Thu, 01 Dec 2022 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was watching a &lt;a href=&quot;https://www.youtube.com/watch?v=1rFlhFbJ1_s&quot;&gt;recording of José Valim livecoding solutions to the 2021 Advent of Code problems&lt;/a&gt; and I noticed a piece of code that I didn’t know was valid Elixir syntax.&lt;/p&gt;
&lt;p&gt;In Elixir, anonymous functions can use pattern matching on their input to execute different code based on the match.&lt;/p&gt;
&lt;p&gt;This works similarly to a cond statement:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://til.ashleyconnor.co.uk/_astro/ec.787mv.css&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;cond&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;This will not be true&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Nor this&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;But this will&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cond do  2 + 2 == 5 -&gt;    &amp;quot;This will not be true&amp;quot;  2 * 2 == 3 -&gt;    &amp;quot;Nor this&amp;quot;  1 + 1 == 2 -&gt;    &amp;quot;But this will&amp;quot;end&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This pattern matching capability enables code like this from the video:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;split&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;trim:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Enum&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;fn&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;forward &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; number &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;:forward&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;to_integer&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(number)}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;down &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; number &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;:down&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;to_integer&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(number)}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;up &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; number &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;:up&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;to_integer&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(number)}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Enum&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;reduce&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#919AA3&quot;&gt;_depth&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#919AA3&quot;&gt;_position&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}, &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;fn&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;:forward&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, value}, {depth, position} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {depth, position &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; value}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;:down&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, value}, {depth, position} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {depth &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; value, position}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;:up&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, value}, {depth, position} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {depth &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; value, position}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {depth, position} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; depth &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; position &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;input|&gt; String.split(&amp;quot;\n&amp;quot;, trim: true)|&gt; Enum.map(fn  &amp;quot;forward &amp;quot; &lt;&gt; number -&gt; {:forward, String.to_integer(number)}  &amp;quot;down &amp;quot; &lt;&gt; number -&gt; {:down, String.to_integer(number)}  &amp;quot;up &amp;quot; &lt;&gt; number -&gt; {:up, String.to_integer(number)}end)|&gt; Enum.reduce({ _depth = 0, _position = 0}, fn  {:forward, value}, {depth, position} -&gt; {depth, position + value}  {:down, value}, {depth, position} -&gt; {depth + value, position}  {:up, value}, {depth, position} -&gt; {depth - value, position}end)|&gt; then(fn {depth, position} -&gt; depth * position end)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded><category>elixir</category></item><item><title>How to remove Self Control</title><link>https://til.ashleyconnor.co.uk/2022-11-26-how-to-remove-self-control/</link><guid isPermaLink="true">https://til.ashleyconnor.co.uk/2022-11-26-how-to-remove-self-control/</guid><pubDate>Sat, 26 Nov 2022 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was toying with applications that block time-wasting websites in the hope that the friction would lead me to be more productive.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://selfcontrolapp.com/&quot;&gt;Self Control&lt;/a&gt; is one solution.&lt;/p&gt;
&lt;p&gt;Annoyingly Self Control isn’t easily stopped once a timer is started, and the application doesn’t come with an uninstaller.&lt;/p&gt;
&lt;p&gt;Usually when uninstalling apps on OSX I make use of a very helpful freeware program &lt;a href=&quot;https://freemacsoft.net/appcleaner/&quot;&gt;App Cleaner&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;App Cleaner found most of the installed files and removed them, however if you’ve already started a blocking timer then there are a few other things that we need to clean up.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stop Self Control from automatically restarting - &lt;code&gt;launchctl unload -w /Library/LaunchDaemons/org.eyebeam.selfcontrold.plist&lt;/code&gt; (App Cleaner had already removed the plist file).&lt;/li&gt;
&lt;li&gt;Kill the Self Control process - &lt;code&gt;sudo killall SelfControl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Remove the timer lock file - &lt;code&gt;sudo rm /etc/SelfControl.lock&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the process dead and unloaded from &lt;a href=&quot;https://www.launchd.info/&quot;&gt;&lt;code&gt;launchd&lt;/code&gt;&lt;/a&gt; we can now remove the firewall rules that were added.&lt;/p&gt;
&lt;p&gt;First edit the root &lt;a href=&quot;https://en.wikipedia.org/wiki/PF_(firewall)&quot;&gt;&lt;code&gt;pf&lt;/code&gt;&lt;/a&gt; config file &lt;code&gt;sudo vim /etc/pf.conf&lt;/code&gt; and remove the &lt;code&gt;load anchor &quot;org.eyebeam&quot; from &quot;/etc/pf.anchors/org.eyebeam&quot;&lt;/code&gt; entry.&lt;/p&gt;
&lt;p&gt;Then remove the anchor file &lt;code&gt;sudo rm /etc/pf.anchors/org.eyebeam&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Reload &lt;code&gt;pf&lt;/code&gt; with &lt;code&gt;sudo pfctl -f /etc/pf.conf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally we need to remove any host entries that Self Control added by removing the Self Control block from the &lt;code&gt;/etc/hosts&lt;/code&gt; file &lt;code&gt;sudo vim /etc/hosts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Websites previously blocked should now be accessible. To overcome DNS caching issues you may need to run &lt;code&gt;sudo killall -HUP mDNSResponder&lt;/code&gt;.&lt;/p&gt;
</content:encoded><category>macos</category></item><item><title>How to run a shell script over images with Automator</title><link>https://til.ashleyconnor.co.uk/2022-11-13-how-to-run-a-shell-script-over-images-with-automator/</link><guid isPermaLink="true">https://til.ashleyconnor.co.uk/2022-11-13-how-to-run-a-shell-script-over-images-with-automator/</guid><pubDate>Sun, 13 Nov 2022 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When posting screenshots of text to Twitter sometimes the thumbnail gets messed up and clips
the content making it unreadable without clicking to expand.&lt;/p&gt;
&lt;p&gt;I was using a handy &lt;a href=&quot;https://gist.github.com/ashleyconnor/ee6481430fc166e4fe8688e54b848c6b&quot;&gt;script&lt;/a&gt; I’d put together that leverages &lt;a href=&quot;https://imagemagick.org/index.php&quot;&gt;ImageMagick&lt;/a&gt; to resize any image to 1600x900px, which is the optimal size for Twitter feeds.&lt;/p&gt;
&lt;p&gt;The script also uses ImageMagick’s histogram feature to fill in any empty space using the dominant color of the image. This is expecially hand when clipping text that has a background other than white, like the &lt;a href=&quot;https://www.ft.com/&quot;&gt;Financial Times&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Executing the script is what this post is about.&lt;/p&gt;
&lt;p&gt;Firing up the command line, looking for the image and running the script with the image path as an argument is tedious.&lt;/p&gt;
&lt;p&gt;It’d be much nicer if we could right click an image or a selection of images and resize them right in Finder.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_macOS_built-in_apps#Automator&quot;&gt;Automator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Automator allows us to create a “Quick Action” which can be accessed using a right-click of a mouse or a two-fingered click of the trackpad.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Quick Action Automator Document Type&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1065&quot; height=&quot;969&quot; src=&quot;https://til.ashleyconnor.co.uk/_astro/quick_action.E_wZ3Bx8_Z299jGU.webp&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the workflow options we will select:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Workflow receives current “Image files” in “any application”&lt;/li&gt;
&lt;li&gt;Choose any “Image”&lt;/li&gt;
&lt;li&gt;Choose any “Color”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then in the Actions side-menu we will search for “Run Shell Script” and drag it into our workflow.&lt;/p&gt;
&lt;p&gt;For the Shell I’ve selected “/bin/bash” and for Pass Input “as arguments”.&lt;/p&gt;
&lt;p&gt;I then paste in &lt;a href=&quot;https://gist.github.com/ashleyconnor/ee6481430fc166e4fe8688e54b848c6b&quot;&gt;my script&lt;/a&gt; from before.&lt;/p&gt;
&lt;p&gt;The workflow then looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Finished Workflow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3248&quot; height=&quot;2112&quot; src=&quot;https://til.ashleyconnor.co.uk/_astro/workflow.CPerzeNF_Z1Vngiq.webp&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then once we save the Quick Action becomes available in our conext menu:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Context menu showing our new quick action&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1274&quot; height=&quot;1054&quot; src=&quot;https://til.ashleyconnor.co.uk/_astro/context_menu.BAOInha2_Z24U1FM.webp&quot;&gt;&lt;/p&gt;
&lt;p&gt;An example of the resize:&lt;/p&gt;
&lt;p&gt;Before&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Before our quick action has processed the image&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1480&quot; height=&quot;646&quot; src=&quot;https://til.ashleyconnor.co.uk/_astro/before.e6Mtbngx_Z23Gg3p.webp&quot;&gt;&lt;/p&gt;
&lt;p&gt;After&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;After our quick action has processed the image&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;900&quot; src=&quot;https://til.ashleyconnor.co.uk/_astro/after.DmU5UuRl_ZLQ13b.webp&quot;&gt;&lt;/p&gt;
</content:encoded><category>macos</category><category>tools</category></item></channel></rss>