<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Karma Computing]]></title><description><![CDATA[Thoughts, stories and ideas.]]></description><link>https://blog.karmacomputing.co.uk/</link><image><url>https://blog.karmacomputing.co.uk/favicon.png</url><title>Karma Computing</title><link>https://blog.karmacomputing.co.uk/</link></image><generator>Ghost 5.28</generator><lastBuildDate>Tue, 07 Apr 2026 16:53:11 GMT</lastBuildDate><atom:link href="https://blog.karmacomputing.co.uk/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[nvidia-smi Failed to initialize NVML: Driver/library version mismatch NVML library version: 535.247]]></title><description><![CDATA[<p>Alternative title: &quot;Help I upgraded my Debian/Ubuntu Linux server and now my expensive GPU does not work, at all, why is that? Also I don&apos;t want to reboot. How can I fix this without rebooting?&quot;<br><br>Faced with the following error:<br></p><pre><code>$ nvidia-smi

Failed to initialize NVML:</code></pre>]]></description><link>https://blog.karmacomputing.co.uk/nvidia-smi-failed-to-initialize-nvml-driver-library-version-mismatch-nvml-library-version-535-247/</link><guid isPermaLink="false">696a9967b93427b5f9b209e3</guid><category><![CDATA[ai-assisted]]></category><category><![CDATA[devops]]></category><category><![CDATA[Sysadmin]]></category><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Fri, 16 Jan 2026 20:22:42 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2026/01/nvidia-smi-failed-to-initalize-amanda-dalbjorn-UbJMy92p8wk-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.karmacomputing.co.uk/content/images/2026/01/nvidia-smi-failed-to-initalize-amanda-dalbjorn-UbJMy92p8wk-unsplash.jpg" alt="nvidia-smi Failed to initialize NVML: Driver/library version mismatch NVML library version: 535.247"><p>Alternative title: &quot;Help I upgraded my Debian/Ubuntu Linux server and now my expensive GPU does not work, at all, why is that? Also I don&apos;t want to reboot. How can I fix this without rebooting?&quot;<br><br>Faced with the following error:<br></p><pre><code>$ nvidia-smi

Failed to initialize NVML: Driver/library version mismatch
NVML library version: 535.247&quot;</code></pre><p>Short answer: You may have inadvertently, during your routine installation of updates/patched ( <code>apt get upgrade</code> etc) your Nvidia kernel module drivers in the process. The loaded kernel module is older than the one on risk, and <code>nvidia-smi</code> is trying to protect/warn you of this fact.</p><p>How do I fix it?</p><h3 id="verify-your-hardware-is-actually-ok-using-lspci">Verify your hardware is actually OK using <code>lspci</code></h3><pre><code>lspci | grep -i nvidia</code></pre><p>If it shows in the output (e.g. <code>01:00.0</code>...) &quot;This means the hardware is alive but the software isn&apos;t talking to it&quot;.</p><p>You could simply reboot, after which, your new dynamicially loaded (newer) nvidia kernel modules will have been loaded. If you don&apos;t want/can&apos;t currently afford to reboot, then you have option still:<br><br>First attempt to unload the nvidia kernel modules:</p><pre><code>sudo rmmod nvidia_uvm
sudo rmmod nvidia_drm
sudo rmmod nvidia_modeset
sudo rmmod nvidia</code></pre><p>You&apos;ll likely observe errors such as <code>rmmod: ERROR: Module nvidia_uvm is in use</code> , to diagnose which processes are currently using the various modules, use <code>lsof /dev/nvidia*</code> and (consider before) kill the processes which come back. So by definition this article is assuming you can&apos;t affor to reboot the server, but you <em>can</em> afford/willing to terminate any and all processes currently trying to use the GPU.</p><p>With those processes killed, you&apos;ll be able to <code>rmmod</code> the drivers</p><pre><code>sudo rmmod nvidia_uvm
sudo rmmod nvidia_drm
sudo rmmod nvidia_modeset
sudo rmmod nvidia</code></pre><p>Then finally, load back the nvidia kernal module - which this time will be the newer (updated) kernel module:</p><pre><code>sudo modprobe nvidia
</code></pre><p>..and verify your GPU is happy and running again with <code>nvidia-smi</code> e.g:</p><pre><code>nvidia-smi
Fri Jan 16 20:01:06 2026       
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.247.01             Driver Version: 535.247.01   CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
|                                         |                      |               MIG M. |
|=========================================+======================+======================|
|   0  Tesla V100-PCIE-16GB           Off | 00000000:82:00.0 Off |                    0 |
| N/A   35C    P0              36W / 250W |      0MiB / 16384MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+
                                                                                         
+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
|  No running processes found                                                           |
+---------------------------------------------------------------------------------------+
</code></pre>]]></content:encoded></item><item><title><![CDATA[qemu-system-x86 Creating an idempotent VM with SSH enabled via cloud-init and qemu monitor enabled over tcp]]></title><description><![CDATA[<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/chrisjsimpson/qemu-system-x86_64-bootstrap-me-an-ubuntu-vm-idempotent"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - chrisjsimpson/qemu-system-x86_64-bootstrap-me-an-ubuntu-vm-idempotent</div><div class="kg-bookmark-description">Contribute to chrisjsimpson/qemu-system-x86_64-bootstrap-me-an-ubuntu-vm-idempotent development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">chrisjsimpson</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/6c71766cccbe189c48f52e81ff587f91ca8e015f25a29f35b7789dba69e85b00/chrisjsimpson/qemu-system-x86_64-bootstrap-me-an-ubuntu-vm-idempotent" alt></div></a></figure><p>The above repo is the result of needing/wanting to be able to quickly bootstrap an Ubuntu VM in an idempotent way. This is especially useful for validating setups/bootstraps of</p>]]></description><link>https://blog.karmacomputing.co.uk/qemu-system-x86-creating-an-idempotent-vm-with-ssh-enabled-via-cloud-init-and-qemu-monitor-enabled-over-tcp/</link><guid isPermaLink="false">695b73a3b93427b5f9b2098d</guid><category><![CDATA[debugging]]></category><category><![CDATA[Sysadmin]]></category><category><![CDATA[open source]]></category><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Mon, 05 Jan 2026 08:32:57 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2026/01/melissa-keizer-fyzZicuzcE8-unsplash-emu-qemu-system-run-in-background-bootstrap-vm-cloud-init.jpg" medium="image"/><content:encoded><![CDATA[<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/chrisjsimpson/qemu-system-x86_64-bootstrap-me-an-ubuntu-vm-idempotent"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - chrisjsimpson/qemu-system-x86_64-bootstrap-me-an-ubuntu-vm-idempotent</div><div class="kg-bookmark-description">Contribute to chrisjsimpson/qemu-system-x86_64-bootstrap-me-an-ubuntu-vm-idempotent development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="qemu-system-x86 Creating an idempotent VM with SSH enabled via cloud-init and qemu monitor enabled over tcp"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">chrisjsimpson</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/6c71766cccbe189c48f52e81ff587f91ca8e015f25a29f35b7789dba69e85b00/chrisjsimpson/qemu-system-x86_64-bootstrap-me-an-ubuntu-vm-idempotent" alt="qemu-system-x86 Creating an idempotent VM with SSH enabled via cloud-init and qemu monitor enabled over tcp"></div></a></figure><img src="https://blog.karmacomputing.co.uk/content/images/2026/01/melissa-keizer-fyzZicuzcE8-unsplash-emu-qemu-system-run-in-background-bootstrap-vm-cloud-init.jpg" alt="qemu-system-x86 Creating an idempotent VM with SSH enabled via cloud-init and qemu monitor enabled over tcp"><p>The above repo is the result of needing/wanting to be able to quickly bootstrap an Ubuntu VM in an idempotent way. This is especially useful for validating setups/bootstraps of lower level hardware , and not having to remember every time all the various (powerful) <a href="https://www.qemu.org/docs/master/system/invocation.html">invocation options provided by Qemu</a>.</p><p>What it does it leave you with a VM running, with SSH enabled/listening using public key authentication (password auth disabled). The disk is expanded by <code>+5G</code> to give you some scratch space, and each time the script is ran the entire setup is blown away (whilst being careful not to re-download an entire cloud-init image once again). To bootstrap ssh access and a valid system user, cloud-init is used- and a &apos;fake&apos; metadata server runs using pythons built-in basic http server ( <code>python3 -m http.server</code>) all this is done for you automatically, however, and the script does some basic tests before running (e.g. do you have enough disk space? Is qemu installed? etc). It does assume you have python3 installed.</p><p>Running qemu in the background proved tricky (there&apos;s more to it than the argument <code>-daemonize</code> if you want to preserve the qemu monitor access (useful) and still have access to the serial output of the VM (useful)). The assumption here is you <em>dont</em> want/need a VGA display (hence <code>-display none</code>) and instead simply want a headless Ubuntu server VM without the hasstle/bloat of firing up VirtualBox, Parallels, VMware etc etc. A key benefit being you can run <code>qemu-system-x86</code> &apos;anywhere&apos; such as locally, or in a CI/CD pipeline to verify a system or as part of a docs automation test to verify your docs work as documented (<a href="https://openzfs.github.io/openzfs-docs">OpenZFS docs</a> have a fabulous approach which does just that to<a href="https://github.com/openzfs/zfs/blob/master/.github/workflows/zfs-qemu.yml"> test their docs with CI + qemu</a>). Anyway, back to the script:<br><br>Once bootstrapped, the VM can be accessed from the host over ssh via:<br></p><pre><code class="language-bash">ssh -p 2222 -i dummykey user1@127.0.0.1</code></pre><p>and the Qemu monitor can be accessed via:</p><pre><code class="language-bash">nc 127.0.0.1 4444
QEMU 8.2.2 monitor - type &apos;help&apos; for more information
(qemu) 
</code></pre><p>The <a href="https://github.com/chrisjsimpson/qemu-system-x86_64-bootstrap-me-an-ubuntu-vm-idempotent/blob/main/doit.sh">qemu script</a> is commented throughout with links to various docs and bash-isms which may not be obvious how/why they work.</p>]]></content:encoded></item><item><title><![CDATA[How to write a systemd unit service file]]></title><description><![CDATA[<p>Remind me how to write a systemd serive and the required steps/Unit file. </p><p>Say you want to run <code><a href="https://rqlite.io/">rqlite</a></code> (any program you want to run as a service) as a systemd service.</p><p>Step one - always check if the maintainer(s) of your program already ship / document a systemd</p>]]></description><link>https://blog.karmacomputing.co.uk/how-to-write-a-systemd-unit-service-file/</link><guid isPermaLink="false">69008fafb93427b5f9b20910</guid><category><![CDATA[debugging]]></category><category><![CDATA[linux]]></category><category><![CDATA[Sysadmin]]></category><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Wed, 29 Oct 2025 11:53:55 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2025/10/how-to-write-a-systemd-service-file-and-debug-it.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.karmacomputing.co.uk/content/images/2025/10/how-to-write-a-systemd-service-file-and-debug-it.jpg" alt="How to write a systemd unit service file"><p>Remind me how to write a systemd serive and the required steps/Unit file. </p><p>Say you want to run <code><a href="https://rqlite.io/">rqlite</a></code> (any program you want to run as a service) as a systemd service.</p><p>Step one - always check if the maintainer(s) of your program already ship / document a systemd confguration. They probably know better than you what reasonable defaults to use. Or a simple Google <code>rqlite systemd</code> brings back a good <a href="https://stackoverflow.com/questions/70013941/how-to-run-rqlite-as-a-service">starter</a>:</p><p></p><p>File path: <code>/etc/systemd/system/rqlite.service</code></p><!--kg-card-begin: markdown--><pre><code>[Unit]
Description=rqlite
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/rqlited -http-addr 0.0.0.0:4001 -raft-addr 0.0.0.0:4002 /path/to/datadir
User=youruser
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGTERM
Restart=always

[Install]
WantedBy=multi-user.target
</code></pre>
<!--kg-card-end: markdown--><p>But what do those options mean?</p><ul><li>The <code>Unit</code> config docs <a href="https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html">https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html</a></li><li>The <code>Service</code> config docs <a href="https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html">https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html</a></li></ul><h2 id="where-do-i-put-the-systemd-service-file">Where do I <em>put</em> the systemd service file?</h2><p>The <a href="https://www.freedesktop.org/software/systemd/man/latest/systemd-system.conf.html">systemd docs</a> state:</p><blockquote>When packages need to customize the configuration, they can install drop-ins under /usr/. Files in /etc/ are reserved for the local administrator, who may use this logic to override the configuration files installed by vendor packages. Drop-ins have to be used to override package drop-ins, since the main configuration file has lower precedence. It is recommended to prefix all filenames in those subdirectories with a two-digit number and a dash, to simplify the ordering. This also defines a concept of drop-in priorities to allow OS vendors to ship drop-ins within a specific range lower than the range used by users. This should lower the risk of package drop-ins overriding accidentally drop-ins defined by users. It is recommended to use the range 10-40 for drop-ins in /usr/ and the range 60-90 for drop-ins in /etc/ and /run/, to make sure that local and transient drop-ins take priority over drop-ins shipped by the OS vendor.<br><br>To disable a configuration file supplied by the vendor, the recommended way is to place a symlink to /dev/null in the configuration directory in /etc/, with the same filename as the vendor configuration file.</blockquote><h3 id="common-pitfalls-mistakes">Common pitfalls / mistakes</h3><ul><li>You don&apos;t know how to see the logs for a failing systemd service. Answer: <code>journalctl -fu &lt;service-name&gt;</code> will tail/follow the logs of your service</li><li>Don&apos;t know the same of the service? Running <code>systemctl</code> will list all units, then you can search them with <code>/</code> and type..</li><li><code>ExecStart</code> , if you pass a script- you forgot to update your paths to use absolute paths rather than relative paths and see erros such as <code>No such file or directory</code> </li></ul><h3 id="how-do-i-make-my-systemd-service-start-at-boot-time">How do I make my systemd service start at boot time?</h3><p>You have to enable it. e.g.:</p><!--kg-card-begin: markdown--><pre><code>systemctl enable rqlite
Created symlink /etc/systemd/system/multi-user.target.wants/rqlite.service &#x2192; /etc/systemd/system/rqlite.service.
</code></pre>
<!--kg-card-end: markdown--><h4 id="how-do-i-know-check-my-systemd-unit-serice-is-configured-to-start-at-boot-time">How do I know/ check my systemd unit serice is configured to start at boot time?</h4><p><br>After running <code>systemctl status rqlite</code> you&apos;ll see &quot;`enabled`&quot; on your unit output</p><!--kg-card-begin: markdown--><pre><code>&#x25CF; rqlite.service - rqlite
     Loaded: loaded (/etc/systemd/system/rqlite.service; enabled; preset: enabled)
    Drop-In: /run/systemd/system/service.d
             &#x2514;&#x2500;zzz-lxc-service.conf
     Active: active (running) since Tue 2025-10-28 11:38:54 UTC; 1min 41s ago
</code></pre>
<!--kg-card-end: markdown--><h3 id="how-do-i-stop-a-systemd-service-starting-at-boot-time">How do I stop a systemd service starting at boot time?</h3><p>Disable it, e.g.:</p><!--kg-card-begin: markdown--><pre><code>systemctl disable rqlite
Removed &quot;/etc/systemd/system/multi-user.target.wants/rqlite.service&quot;.
</code></pre>
<!--kg-card-end: markdown--><p></p><h3 id="typical-commands-to-activateloadrestart-your-new-systemd-service">Typical commands to activate/load/restart your new systemd service</h3><ul><li><code>systemctl daemon-reload</code> when you change your systemd unit service file, you need to reload systemd </li><li><code>journalctl -fu rqlite</code> - look at /follow the logs for your service</li><li><code>systemctl restart rqlite.service</code></li></ul><h3 id="how-do-i-get-the-current-directory-of-my-execstart-script-so-i-dont-have-to-hardcode-it">How do I get the current directory of my <code>ExecStart</code> script so I don&apos;t have to hardcode it?</h3><p>Say you have a shell script to start your systemd service <code>start.sh</code> and you don&apos;t want to hardcode paths to the various config files, you can use a combinsation of <code>$0</code>, <code>dirname</code> and <code>readlpath</code> to determine the path at runtime.</p><p>For example: Say you have: <code>ExecStart=/path/start.sh</code></p><!--kg-card-begin: markdown--><pre><code>#!/bin/bash
set -x
# i/we wrote this not rqlite

SCRIPT_PATH=$(dirname $(realpath $0))

$SCRIPT_PATH/rqlited -auth $SCRIPT_PATH/config.json -node-id=$(cat /etc/machine-id) /path/to/data

</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[incus bulk delete snapshots]]></title><description><![CDATA[<p>Incus in an excellent system container, application container, and virtual machine manager (see <a href="https://linuxcontainers.org/incus/">https://linuxcontainers.org/incus/</a>) which allows you to schedule regular <a href="https://linuxcontainers.org/incus/docs/main/howto/instances_backup/#schedule-instance-snapshots">snapshots</a> of instances. </p><p>If, like me, you like to test these systems. I created a snapshot schedule to snapshot instances every minutes (yes, extreme) but you can</p>]]></description><link>https://blog.karmacomputing.co.uk/incus-bulk-delete-snapshots/</link><guid isPermaLink="false">681643f1b93427b5f9b20896</guid><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Sat, 03 May 2025 16:47:56 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2025/05/incus-bulk-delete-snapshots-franco-antonio-giovanella-PVDWaEhSIAg-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.karmacomputing.co.uk/content/images/2025/05/incus-bulk-delete-snapshots-franco-antonio-giovanella-PVDWaEhSIAg-unsplash.jpg" alt="incus bulk delete snapshots"><p>Incus in an excellent system container, application container, and virtual machine manager (see <a href="https://linuxcontainers.org/incus/">https://linuxcontainers.org/incus/</a>) which allows you to schedule regular <a href="https://linuxcontainers.org/incus/docs/main/howto/instances_backup/#schedule-instance-snapshots">snapshots</a> of instances. </p><p>If, like me, you like to test these systems. I created a snapshot schedule to snapshot instances every minutes (yes, extreme) but you can imagne scnerarios where this is useful (students, learners for example). When you do this, however, after a few weeks of course you can end up with tens of thousands of snapshots (especially if you don&apos;t set an expiry on the snapshots). <code>incus snapshot list</code> becomes painfully slow, because an incus api <code>get snapshot</code> is called for every single snapshot (esssentially a <code>O(n)</code> operation proportional to the number of snapshots).<br></p><pre><code>With excessive amounts of snapshots , `incus snapshot list &lt;instance-name&gt;` will eventually timeout:

```
incus snapshot list instance-name
^B^[[BError: Get &quot;http://unix.socket/1.0/instances/instance-name/snapshots?recursion=1&quot;: net/http: timeout awaiting response headers
```</code></pre><p>Even if you delete your snapshots as the zfs level directly ( <code>zfs destroy</code> ...) incus state still has a database entry to those non existant snapshots.</p><p></p><blockquote>the best bet is to use zfs destroy to directly delete all those snapshots. That should then make ZFS performance go back to normal at which point you can issue the incus snapshot delete commands to get rid of the Incus snapshots.<br>Src: <a href="https://github.com/lxc/incus/issues/2036#issuecomment-2842758126">https://github.com/lxc/incus/issues/2036#issuecomment-2842758126</a></blockquote><p>Since snapshots are deleted serially, even using tools like gnu parallel won&apos;t give you speed boost so a simple bash for loop will <em>eventually </em>clear out Incus&apos;s database for that particular instance (rince &amp; repeat for other instances):</p><p></p><pre><code class="language-bash">#!/bin/bash

set -x

# whatever your range to delete
for i in {7000..16053}; do

incus snapshot delete instance-name snap$i;

done</code></pre><p><br><br>See also</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/lxc/incus/issues/2036#issuecomment-2842758126"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Bulk deletion of expired snapshots / deleting many snapshots serially is impractically slow &#xB7; Issue #2036 &#xB7; lxc/incus</div><div class="kg-bookmark-description">Is there an existing issue for this? There is no existing issue for this feature What are you currently unable to do Related to #1837 Problem statement: When instance(s) have many thounsands of sna...</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="incus bulk delete snapshots"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">lxc</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/f2bc9f84785f158461fb61bb2b9425109e493fafdfa67dc23a54e92d813a96d5/lxc/incus/issues/2036" alt="incus bulk delete snapshots"></div></a></figure><p></p>]]></content:encoded></item><item><title><![CDATA[git list previous branch]]></title><description><![CDATA[<p>In <code>git</code>, how do I go back to the previous branch I was just on? I&apos;ve got a memory of a fish and easily forget which branch I was on previously- how do I switch back? Also, <a href="https://www.sciencedirect.com/science/article/abs/pii/0091305776900708">is it true fish have short memories</a> and what if they&</p>]]></description><link>https://blog.karmacomputing.co.uk/git-list-previous-branch/</link><guid isPermaLink="false">6783d612b93427b5f9b20855</guid><category><![CDATA[debugging]]></category><category><![CDATA[programming]]></category><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Sun, 12 Jan 2025 14:57:14 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2025/01/git-find-last-branch-name-jachan-devol-xDPLiRQchx8-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.karmacomputing.co.uk/content/images/2025/01/git-find-last-branch-name-jachan-devol-xDPLiRQchx8-unsplash.jpg" alt="git list previous branch"><p>In <code>git</code>, how do I go back to the previous branch I was just on? I&apos;ve got a memory of a fish and easily forget which branch I was on previously- how do I switch back? Also, <a href="https://www.sciencedirect.com/science/article/abs/pii/0091305776900708">is it true fish have short memories</a> and what if they&apos;re drunk?</p><p>An aswer to finding the name of the previous branch you were on is: </p><pre><code>git name-rev @{-1} --name-only</code></pre><p>Will show you the last branch you were on in terminal.<br><br>Source: <a href="https://stackoverflow.com/a/59766367">https://stackoverflow.com/a/59766367</a></p><p>See also Scott Stafford&apos;s longer post wish alias setup examples:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://ses4j.github.io/2020/04/01/git-alias-recent-branches/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">List your most recently-used branches using Git</div><div class="kg-bookmark-description">Set up a git alias that uses the reflog to show what branches you have most recently been using</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://t1.gstatic.com/faviconV2?client=SOCIAL&amp;type=FAVICON&amp;fallback_opts=TYPE,SIZE,URL&amp;url=https://github.io/2020/04/01/git-alias-recent-branches/&amp;size=128" alt="git list previous branch"><span class="kg-bookmark-author">Scott Stafford</span><span class="kg-bookmark-publisher">Scott Stafford</span></div></div></a></figure>]]></content:encoded></item><item><title><![CDATA[How can I create a minimal NodeJS script. mjs? What's that?]]></title><description><![CDATA[<p>TIL <code>.mjs</code> is a thing, since when?<br><br>When running my script (e.g. <code>node myscript.js</code> ) I see the error &quot;<code>SyntaxError: Cannot use import statement outside a module</code>&quot;, why?<br><br>I write a lot of Python, and I&apos;m used to (like in <code>bash</code>) writing quick little scripts</p>]]></description><link>https://blog.karmacomputing.co.uk/mjs-whats-that-how-can-i-create-a-minimal-nodejs-script/</link><guid isPermaLink="false">67795ae7b93427b5f9b207ef</guid><category><![CDATA[programming]]></category><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Sat, 04 Jan 2025 16:16:15 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2025/01/whats-an-mjs-file-nick-fewings-noY6T_AsVSo-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.karmacomputing.co.uk/content/images/2025/01/whats-an-mjs-file-nick-fewings-noY6T_AsVSo-unsplash.jpg" alt="How can I create a minimal NodeJS script. mjs? What&apos;s that?"><p>TIL <code>.mjs</code> is a thing, since when?<br><br>When running my script (e.g. <code>node myscript.js</code> ) I see the error &quot;<code>SyntaxError: Cannot use import statement outside a module</code>&quot;, why?<br><br>I write a lot of Python, and I&apos;m used to (like in <code>bash</code>) writing quick little scripts to perform a task, and runing them with <code>python mything.py</code>. So I expected the same thing with <code>node mything.js</code> would be possible with NodeJS.</p><p>I wanted to quickly parse some YAML in <code>node</code> so I discored the <a href="https://www.npmjs.com/package/yaml">YAML node package</a>, followed it&apos;s README and wrote something like this:</p><pre><code>import fs from &apos;fs&apos;
import YAML from &apos;yaml&apos;

YAML.parse(&apos;[ true, false, maybe, null ]\n&apos;)
// [ true, false, &apos;maybe&apos;, null ]

const file = fs.readFileSync(&apos;./file.yml&apos;, &apos;utf8&apos;)
console.log(YAML.parse(file))</code></pre><p>But if you do that, and try to run with <code>node mything.py</code> you&apos;ll see the error:</p><pre><code>$ node test.js 
(node:603976) Warning: To load an ES module, set &quot;type&quot;: &quot;module&quot; in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
mything.js:1
import fs from &apos;fs&apos;
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:128:18)
    at wrapSafe (node:internal/modules/cjs/loader:1280:20)
    at Module._compile (node:internal/modules/cjs/loader:1332:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1427:10)
    at Module.load (node:internal/modules/cjs/loader:1206:32)
    at Module._load (node:internal/modules/cjs/loader:1022:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
    at node:internal/main/run_main_module:28:49

Node.js v20.12.0</code></pre><p>Turns out you can, as the error message suggests, name your script with a <code>.mjs</code> extention to make your intentions explicit. So <code>mything.js</code> becomes <code>mything.mjs</code>, and away we go! No error, and we have our handy script in NodeJS. No need to do any extra work.</p><pre><code>$ # Our script now runs as expected
$ node test.mjs 
{ snickers: &apos;GO_ON_THEN&apos; }</code></pre><h4 id="see-also"><br>See also</h4><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://blog.karmacomputing.co.uk/what-is-ejs-and-why-do-i-need-it/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">What is EJS and why do I need it?</div><div class="kg-bookmark-description">EJS is a templating engine for for JavaScript. So, font-end stuff. It seems pretty laissez-faire in that it doesn&#x2019;t tell you how to organisethings. Ultimately, EJS is a tool to generate HTML markup with plain Javascript. The general ideaSend your content to the browser delivered as js, in</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://blog.karmacomputing.co.uk/favicon.ico" alt="How can I create a minimal NodeJS script. mjs? What&apos;s that?"><span class="kg-bookmark-author">Karma Computing</span><span class="kg-bookmark-publisher">Christopher Simpson</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://blog.karmacomputing.co.uk/content/images/2017/10/ken-treloar-346065.jpg" alt="How can I create a minimal NodeJS script. mjs? What&apos;s that?"></div></a></figure><p>Releated links:</p><ul><li><a href="https://stackoverflow.com/questions/57492546/what-is-the-difference-between-js-and-mjs-files">What is the difference between .js and .mjs files?</a></li></ul>]]></content:encoded></item><item><title><![CDATA[What is a 'cost function' in Machine Learning / ML]]></title><description><![CDATA[<p>I don&apos;t really know, deeply what a cost functino is in Machine Learning. Let&apos;s learn it. <br>All quotes are from the excellent &quot;Hands-On Machine Learning with Scikit-Learn, and TensorFlow, 1st Edition&quot; unless otherwise stated.</p><p>In &quot;Hands-On Machine Learning with Scikit-Learn, and TensorFlow, 1st</p>]]></description><link>https://blog.karmacomputing.co.uk/what-is-a-cost-function-in-machine-learning-ml/</link><guid isPermaLink="false">66d328bfb93427b5f9b2071d</guid><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Thu, 14 Nov 2024 21:37:39 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2024/11/what-is-a-cost-function.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.karmacomputing.co.uk/content/images/2024/11/what-is-a-cost-function.jpg" alt="What is a &apos;cost function&apos; in Machine Learning / ML"><p>I don&apos;t really know, deeply what a cost functino is in Machine Learning. Let&apos;s learn it. <br>All quotes are from the excellent &quot;Hands-On Machine Learning with Scikit-Learn, and TensorFlow, 1st Edition&quot; unless otherwise stated.</p><p>In &quot;Hands-On Machine Learning with Scikit-Learn, and TensorFlow, 1st Edition&quot;, a cost function is defined as:</p><blockquote>&quot;You can either define a <em>utility function</em> (or <em>fitness function</em>) that measures how <em>good</em> your model is, or you can define a <strong><em>cost function</em></strong><em> </em>that measures how <em>bad</em> it is. For linear regression problems, people typically use a <strong><em>cost function</em></strong> that measures the distance between the linear model&apos;s predictions and the training examples; the objective is to minimize this distance.&quot;<br>- Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow, 2nd Edition, 2017, Aurelien Geron</blockquote><p>As I&apos;m reading this I ask myself:</p><!--kg-card-begin: markdown--><ul>
<li>How can a &apos;cost function&apos; determine what is a good model vs a bad model: What&apos;s it comparing/looking at? How does the function &apos;know&apos; or &apos;calculate&apos; that, and how can we &apos;make&apos; or &apos;create&apos; a function which measures &apos;goodness/badness&apos; of a model.
<ul>
<li>I like I&apos;m now aware sometimes people create functions which measure how <em>good</em> a model is (aka &quot;a utility function (or fitness function) that measures how good your model&quot;)</li>
<li>I&apos;m starting to imagine, perhaps the <em>output</em> of these &apos;cost functions&apos; might be like a &apos;hey, that model measurement is 10% correct for a utility function, or 10% bad for a cost function. Or maybe it&apos;s more often a expressed number say, 1 meaning 100% correct or 0.5 meaning 50% bad. Let&apos;s func out. Do cost functinos evaluate the model &apos;goodness&apos; as a whole, or individual measurements?</li>
<li>Almost. Here&apos;s <a href="https://github.com/ageron/handson-ml/blob/master/math_linear_algebra.ipynb">some realistic examples</a> from the experts</li>
</ul>
</li>
<li>Let&apos;s break the definition down further</li>
</ul>
<!--kg-card-end: markdown--><blockquote>&quot;For linear regression problems, people typically use a <strong><em>cost function</em></strong> that measures the distance between the linear model&apos;s predictions and the training examples; the objective is to minimize this distance.&quot;</blockquote><p>OK that&apos;s great if you come from a mathmetics background. I&apos;m left with the following:</p><ul><li>How does one &apos;measure the distance between the linear model&apos;s predictions and the training examples?&apos;</li><li>I don&apos;t like that sometimes these explainations read (to me) as a sentiant alive thing, that can be &apos;fed&apos; information and &apos;do things&apos; too vuage. &quot;You feed it your training examples and it finds the parameters that make the linear model fit best your data&quot;</li></ul><p>We need to know what Vectors are, this is the best explanation of &apos;<a href="https://github.com/ageron/handson-ml/blob/master/math_linear_algebra.ipynb">What is a vector&apos; I&apos;ve read</a> which uses a Rocket &#x1F680; as an example, all the way to why you&apos;re not killing it on YouTube with your Subscribers (how Google evaluates spammy video content vs engaging cotent), what could be more fun? </p><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2024/08/664248e5-42f2-40c1-83cf-dd5b1344ae74.png" class="kg-image" alt="What is a &apos;cost function&apos; in Machine Learning / ML" loading="lazy" width="2000" height="990" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2024/08/664248e5-42f2-40c1-83cf-dd5b1344ae74.png 600w, https://blog.karmacomputing.co.uk/content/images/size/w1000/2024/08/664248e5-42f2-40c1-83cf-dd5b1344ae74.png 1000w, https://blog.karmacomputing.co.uk/content/images/size/w1600/2024/08/664248e5-42f2-40c1-83cf-dd5b1344ae74.png 1600w, https://blog.karmacomputing.co.uk/content/images/2024/08/664248e5-42f2-40c1-83cf-dd5b1344ae74.png 2384w" sizes="(min-width: 720px) 720px"></figure><p>Above is a visualization using Python and Matplotlib to demonstrate vectors as points in different dimensions:</p><ul><li><strong>Left Plot (2D):</strong> Shows a 2D coordinate plane with a point at (3, 4) and an arrow from the origin to this point, representing the vector.</li><li><strong>Right Plot (3D):</strong> Displays a 3D coordinate system with a single point at (1, 2, 3), representing the vector as a point in 3D space.</li></ul><div class="kg-card kg-toggle-card" data-kg-toggle-state="close"><div class="kg-toggle-heading"><h4 class="kg-toggle-heading-text">Code for the plots above</h4><button class="kg-toggle-card-icon"><svg id="Regular" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path class="cls-1" d="M23.25,7.311,12.53,18.03a.749.749,0,0,1-1.06,0L.75,7.311"/></svg></button></div><div class="kg-toggle-content"><p><br>```</p><p>import matplotlib.pyplot as plt</p><p>import numpy as np</p><p>from mpl_toolkits.mplot3d import Axes3D</p><p># Create a figure for plotting</p><p>fig = plt.figure(figsize=(12, 6))</p><p># 2D Plot on the left</p><p>ax1 = fig.add_subplot(121)</p><p>ax1.set_title(&apos;2D Vector as Point and Arrow&apos;)</p><p>ax1.set_xlabel(&apos;X&apos;)</p><p>ax1.set_ylabel(&apos;Y&apos;)</p><p># Plotting a point (3, 4) and an arrow from origin to that point</p><p>ax1.plot(3, 4, &apos;ro&apos;) # Point at (3,4)</p><p>ax1.arrow(0, 0, 3, 4, head_width=0.3, head_length=0.3, fc=&apos;blue&apos;, ec=&apos;blue&apos;) # Arrow from origin to (3,4)</p><br><p># Annotating the point</p><p>ax1.text(3.2, 4, &apos;P(3, 4)&apos;, fontsize=12)</p><p># 3D Plot on the right</p><p>ax2 = fig.add_subplot(122, projection=&apos;3d&apos;)</p><p>ax2.set_title(&apos;3D Point Representation&apos;)</p><p>ax2.set_xlabel(&apos;X&apos;)</p><p>ax2.set_ylabel(&apos;Y&apos;)</p><p>ax2.set_zlabel(&apos;Z&apos;)</p><br><p># Plotting a point (1, 2, 3)</p><p>ax2.scatter(1, 2, 3, color=&apos;red&apos;)</p><p>ax2.text(1.1, 2, 3, &apos;Point (1, 2, 3)&apos;, fontsize=12)</p><br><p># Display the plot</p><p>plt.tight_layout()</p><p>plt.show()</p><p>```<br></p></div></div>]]></content:encoded></item><item><title><![CDATA[Engineering Principles & Values]]></title><description><![CDATA[<p>A work in progress. (started ~2022 and sat in draft state for far to long) so I&apos;ve decided to publish and intend to revisit. </p><h1 id="empathy-for-learning">Empathy for learning</h1><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Code is never the challenge. Well-rested comfortable people who feel emotionally safe have solved every problem I&#x2019;ve put in</p></blockquote></figure>]]></description><link>https://blog.karmacomputing.co.uk/engineering-principles/</link><guid isPermaLink="false">63ce784cb93427b5f9b1f2b2</guid><category><![CDATA[thinking fast and slow]]></category><category><![CDATA[programming]]></category><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Thu, 14 Nov 2024 21:30:36 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2024/11/sapling-engineering-principles-values.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.karmacomputing.co.uk/content/images/2024/11/sapling-engineering-principles-values.jpg" alt="Engineering Principles &amp; Values"><p>A work in progress. (started ~2022 and sat in draft state for far to long) so I&apos;ve decided to publish and intend to revisit. </p><h1 id="empathy-for-learning">Empathy for learning</h1><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Code is never the challenge. Well-rested comfortable people who feel emotionally safe have solved every problem I&#x2019;ve put in front of them.</p>&#x2014; Ceej &quot;oh well&quot; Silverio (@ceejbot) <a href="https://twitter.com/ceejbot/status/761569569802551300?ref_src=twsrc%5Etfw">August 5, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Unhelpful things to say to engineers:</p><ul><li>Have you finished the issue yet?</li></ul><p>Helpful things to ask engineers:</p><ul><li>Do you need anything?</li></ul><h1 id="complexity-is-the-enemy">Complexity is the enemy</h1><p><em>Unmanaged</em> complexity is the enemy.</p><blockquote>The purpose of <em><strong>abstraction</strong></em> is not to be vague, but to create a new semantic level in which one can be absolutely precise.<br>- <a href="https://wiki.c2.com/?EwDijkstraQuotes">Dijkstra on abstraction</a></blockquote><figure class="kg-card kg-image-card"><img src="https://lh4.googleusercontent.com/2q-YHev-Ebm0bGinvJFWkCVo_y0uguULVmimQb9Nub7v1iCXn-SKF6-lY6w0eizttNo29VnmRq_z__taPaddTeQpWMAGzwwaVg06SqvAyrGykn_tzs-WmxsGnK7nCrpeyc71HP9A9uGqUeBZkTIiqDe0t4-gdPhrIJ9BpJRMQh4YFCPEddRVO9O_5OJfgQ" class="kg-image" alt="Engineering Principles &amp; Values" loading="lazy" width="129" height="164"></figure><h1 id="focus">Focus</h1><p>You know this feeling. Flow is that state where you reach peak creativeness, and time passes without you realising- you <em>may </em>be your most productive during that time. You will certainly be in-flow, but won&apos;t necessarily be aware of being in it. <br><br>Protect time to allow you to enter the flow state.</p><figure class="kg-card kg-embed-card kg-card-hascaption"><iframe src="https://embed.ted.com/talks/mihaly_csikszentmihalyi_flow_the_secret_to_happiness" width="560" height="316" frameborder="0" scrolling="no" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe><figcaption><a href="https://en.wikipedia.org/wiki/Mihaly_Csikszentmihalyi">Mihaly_Csikszentmihalyi</a> on flow.</figcaption></figure><p>Example of concentration in programming, similar to being in flow:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://lh4.googleusercontent.com/nNhYUM9O4ff4Le9TMoIe_lfYfkJxnB0VeL61ke55hGHcsaw7cjtT_r_NT_ta4Vio8gRXW8U7hIqqNXTpewZhnzCljA3cEAOD_x4YnFsEHNNFmOum7SkqJqYSjGPMqAwEnLOiJMDRipG7UxNlmi0iNz0-EDV0OktHWGPEvt62Z6L11AtpggAlQu1tdx1vgw" class="kg-image" alt="Engineering Principles &amp; Values" loading="lazy" width="252" height="967"><figcaption>Concentration isn&apos;t the same as being in flow, but many people will be in flow when they are doing their craft. Notice I don&apos;t write <em>programmers</em>- flow is a human state of mind, regardless of discipline&#xA0;</figcaption></figure><h1 id="robustness">Robustness</h1><p>To borrow from Dijkstra again:</p><blockquote>&quot;Program testing can best show the presence of errors but never their absence.&quot; <br>- <a href="https://wiki.c2.com/?EwDijkstraQuotes">Dijkstra on abstraction</a></blockquote><p>Unit tests &#x2764;&#xFE0F; companionship- not isolation.</p><p>So what&apos;s the value?</p><p>Unit tests provide <strong><em>fast feedback</em>.</strong></p><p>Integration tests and end-to-end testing <strong><em>help prove your product does a job. </em></strong>Unit tests can help provide fast, relevant, contextual assurance whilst you&apos;re refactoring<em> </em>whereas end-toend intergration testing provides equally valuable feedback your shipped produce/service still works as a whole.</p><p>You need <u><strong>both</strong></u> because:</p><!--kg-card-begin: markdown--><ul>
<li>Integration tests can take a long time to run.
<ul>
<li>Use unit tests to do a quick pass</li>
<li>You shouldn&apos;t need to wait 20mins / 1 hour to find out something small broke.</li>
<li>Run unit tests earliest in your build process</li>
<li>Fail the build early as possible</li>
</ul>
</li>
</ul>
<!--kg-card-end: markdown--><p>When you have unit tests but no integration tests:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.karmacomputing.co.uk/content/images/2023/01/When-you-have-unit-tests-but-no-integration-tests-Imgur-2.gif" class="kg-image" alt="Engineering Principles &amp; Values" loading="lazy" width="400" height="400"><figcaption>When you have unit tests but no integration tests <a href="https://www.shapeblue.com/integration-testing-within-cloudstack-marvin/">Source</a></figcaption></figure><p>You&apos;ve locked the door, right? </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.karmacomputing.co.uk/content/images/2023/01/1541174074683725.gif" class="kg-image" alt="Engineering Principles &amp; Values" loading="lazy" width="444" height="250"><figcaption>Tests can give you a very false sense of confidence. <a href="https://www.shapeblue.com/integration-testing-within-cloudstack-marvin/">Source</a></figcaption></figure><p></p><h1 id="running-code">Running Code</h1><blockquote>&#x201C;We reject kings, presidents and voting. We believe in rough consensus and running code&#x201D;<br>- <a href="https://www.ietf.org/proceedings/66/slides/newcomer-1/sld2.htm ">Dave Clark, IETF / MIT </a></blockquote><h1 id="trust-but-verify">Trust but verify</h1><p>Example:</p><ul><li>&quot;Hey, I fixed the issues&quot;</li></ul><p>vs</p><ul><li>Notification: &quot;Fixed &#xA0;#123 Issue forgotten password functionality not sending email &#xA0;link: example.com/issue/123.git &#xA0;build passing with new test: example.com/build/123/run/1</li></ul><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[FastHTML getting started & comparison with Flask]]></title><description><![CDATA[<h3 id="fasthtml-is-built-on-top-of-the-popular-python-libraries-starlette-and-uvicorn-fasthtml-introduces-python-types-for-common-html-elements-integrated-with-htmx-which-means-you-dont-need-to-write-html-templates-directly-and-save-a-lot-of-time-in-theory">FastHTML is built on-top of the popular python libraries <a href="https://www.starlette.io/">starlette</a>, and <a href="https://www.uvicorn.org/">uvicorn</a>. <a href="https://github.com/AnswerDotAI/fasthtml">FastHTML</a> introduces Python types for common <a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/HTML_basics">HTML</a> elements integrated with <a href="https://htmx.org/">HTMX</a> which means you don&apos;t need to write html templates directly, and save a lot of time (in theory).</h3><p></p><p>It&apos;s like traditional HTML, meets</p>]]></description><link>https://blog.karmacomputing.co.uk/fasthtml-getting-started-comparison-with-flask/</link><guid isPermaLink="false">66ae3a53b93427b5f9b20379</guid><category><![CDATA[programming]]></category><category><![CDATA[open source]]></category><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Sun, 04 Aug 2024 18:22:20 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2024/08/web-frame-works-mem-graph.png" medium="image"/><content:encoded><![CDATA[<h3 id="fasthtml-is-built-on-top-of-the-popular-python-libraries-starlette-and-uvicorn-fasthtml-introduces-python-types-for-common-html-elements-integrated-with-htmx-which-means-you-dont-need-to-write-html-templates-directly-and-save-a-lot-of-time-in-theory">FastHTML is built on-top of the popular python libraries <a href="https://www.starlette.io/">starlette</a>, and <a href="https://www.uvicorn.org/">uvicorn</a>. <a href="https://github.com/AnswerDotAI/fasthtml">FastHTML</a> introduces Python types for common <a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/HTML_basics">HTML</a> elements integrated with <a href="https://htmx.org/">HTMX</a> which means you don&apos;t need to write html templates directly, and save a lot of time (in theory).</h3><img src="https://blog.karmacomputing.co.uk/content/images/2024/08/web-frame-works-mem-graph.png" alt="FastHTML getting started &amp; comparison with Flask"><p></p><p>It&apos;s like traditional HTML, meets <a href="https://book.realworldhaskell.org/read/types-and-functions.html">strong</a>er typing, meets niche strongly typed web frameworks (<a href="https://elm-lang.org/">ELM</a> / <a href="https://www.yesodweb.com/">Yesod</a>), meets the simplicity of <a href="http://vanilla-js.com/">VanillaJS</a> with the practicality and mass-market adoption appeal of the <a href="https://stackoverflow.blog/2023/01/26/comparing-tag-trends-with-our-most-loved-programming-languages/">Python</a> ecosystem without learning curve of Rust. If <em>I </em>could borrow some of your time, here&apos;s my notes and musings on this exciting FastHTML thing.<br></p><p>A quick example FastHTML snippet below to illustrate the Python types for common HTML elements the framework defines. I&apos;ve <em>intentionally </em>been <a href="https://peps.python.org/pep-0020/#:~:text=Explicit%20is%20better%20than%20implicit.">explicit</a>* with the python imports to make it clear to the reader/learner what is provided by FastHTML.<br></p><figure class="kg-card kg-code-card"><pre><code class="language-python">from fasthtml.common import fast_app, serve, Div, A

app, rt = fast_app(live=False)


@rt(&quot;/&quot;)
def get():
    return Div(A(&apos;Wikipedia&apos;, href=&quot;https://www.wikipedia.org/&quot;))

serve()</code></pre><figcaption>main.py with <code>pip install python-fasthtml</code> See answerdotai/fasthtml Github</figcaption></figure><blockquote>*Nit: I discourage the use of <code>import *</code> - <em>especially</em> tutorials where it adds ambiguity and hinders learning. Try not to use <code>import *</code>. It&apos;s <a href="https://docs.python.org/3/tutorial/modules.html#:~:text=it%20is%20still%20considered%20bad%20practice%20in%20production%20code">cited as bad practice</a> in production code also.</blockquote><p><br>Generates the following html out-of-the-box with FastHTML:</p><figure class="kg-card kg-code-card"><pre><code>&lt;!doctype html&gt;&lt;/!doctype&gt;

&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;FastHTML page&lt;/title&gt;
    &lt;meta charset=&quot;utf-8&quot;&gt;&lt;/meta&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1, viewport-fit=cover&quot;&gt;&lt;/meta&gt;
    &lt;script src=&quot;https://unpkg.com/htmx.org@next/dist/htmx.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/gh/answerdotai/surreal@1.3.0/surreal.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/gh/gnat/css-scope-inline@main/script.js&quot;&gt;&lt;/script&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/@picocss/pico@latest/css/pico.min.css&quot;&gt;
    &lt;style&gt;:root { --pico-font-size: 100%; }&lt;/style&gt;
  &lt;/head&gt;
  &lt;body&gt;
&lt;div&gt;
  &lt;a href=&quot;http://google.com&quot;&gt;wikipedia&lt;/a&gt;
&lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><figcaption>The minimal FastHTML default html output, plus a rendered Div element with a containing A tag linking to Wikipedia.</figcaption></figure><p>Consequently, when working with FastHTML (or JSx or Jinja for that matter) find yourself living in <code>view-source:<a href="http://127.0.0.1:5001/">http://127.0.0.1:5001/</a>?</code> to <em>see</em> the rendered HTML to visualise/debug it as you&apos;re working. </p><p>Notice that the default FastHTML page render always sends to the browser the following:</p><ul><li>A boilerplate HTML structure including <code>&lt;!doctype html&gt;</code>*</li><li>htmx Javascript from the <a href="https://htmx.org/">htmx project</a></li><li>surreal.js which is a &quot;Mini jQuery alternative&quot; - &#xA0;<a href="https://github.com/answerdotai/surreal">forked</a> by AnswerDotAI of <a href=" https://github.com/gnat/surreal">gnat/surreal</a> project, but appears maintained by same author. </li><li>css-scope-inline which is &quot;Scope your inline style tags in pure vanilla CSS&quot; <a href="https://github.com/gnat/css-scope-inline">gnat/css-scope-inline</a></li><li><a href="https://picocss.com/">Picocss</a> - &quot;Minimal CSS Framework&quot;<br></li></ul><p>For when it matters, in total it&apos;s only about 40.7Kb, (see <a href="https://danluu.com/web-bloat/">How web bloat impacts users with slow connections</a>). If you&apos;re curious about <em>on-device </em>footprints being small (such as in low-powered electronics needing web endpoints), see <a href="miguelgrinberg.com">Miguel</a> Grinberg&apos;s <a href="https://blog.miguelgrinberg.com/post/microdot-yet-another-python-web-framework">Microdot</a> project which is &quot;Small enough to work with MicroPython, while also being compatible with CPython&quot;.</p><blockquote>*(psst.. line 1 this is the first time I&apos;ve seen a closing tag for <code>&lt;/!doctype&gt;</code>, is that even valid HTML? Answer: <a href="https://html.spec.whatwg.org/multipage/syntax.html#the-doctype">Apparently not</a>, still not 100% sure. Issue <a href="https://github.com/AnswerDotAI/fasthtml/issues/179">raised</a>, and <a href="https://github.com/AnswerDotAI/fasthtml/issues/179#issuecomment-2267234734">fixed</a>&#x1F680;- thanks Jeremy!) </blockquote><h2 id="htmx-instant-speed-satisfaction-%E2%9A%A1">HTMx Instant speed satisfaction &#x26A1;</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.karmacomputing.co.uk/content/images/2024/08/htmx-ajax-todo-example.gif" class="kg-image" alt="FastHTML getting started &amp; comparison with Flask" loading="lazy" width="544" height="350"><figcaption>Simplicity of HTML decorated with tags for seamless ajax support using HTMx toggling tasks Done/Not done.</figcaption></figure><p>Full code from the above screenshot is at:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/KarmaComputing/minimal-FastHTML-quickstart"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - KarmaComputing/minimal-FastHTML-quickstart</div><div class="kg-bookmark-description">Contribute to KarmaComputing/minimal-FastHTML-quickstart development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="FastHTML getting started &amp; comparison with Flask"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">KarmaComputing</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/6e8b3d7f4f74f3cf2d9c51eb49025875d0ba0b55e438e35133cd65e2eaace42d/KarmaComputing/minimal-FastHTML-quickstart" alt="FastHTML getting started &amp; comparison with Flask"></div></a></figure><p>When wanting to perform traditional &#xA0;<code>GET</code> / <code>POST</code> / <code>PUT</code> (etc) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods">HTTP methods</a>, FastHTML uses HTMx for its abstractions over <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data#:~:text=In%20the%20early%20days%2C%20this%20general%20technique%20was%20known%20as"><code>Ajax</code>/ <code>fetch</code></a>. You get a very quick dopamine hit the first time you experience the coming-together of HTMx and HTML. The reduction of moving parts, without <a href="https://www.youtube.com/watch?v=rlUjHu3H_L4">compromising</a> benefits.<br></p><blockquote>&#x201C;Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.&#x201D;<br>&#x2015; Antoine de Saint-Exup&#xE9;ry, Airman&apos;s Odyssey</blockquote><p>I&apos;d like to stress these ajax-y/fetch benefits are coming from the HTMx project which stands in its own right. HTMx can be used in <em>any</em> web project including other languages/frameworks - without needing FastHTML. I encourage you to check it out, especially their twitter: <a href="https://x.com/htmx_org">@htmx_org</a>. What&apos;s elegant about FastHTML is the HTML <a href="https://github.com/AnswerDotAI/fasthtml/blob/cf1b6e525b52247e398373c9dad96dcdcd3c20d5/fasthtml/components.py#L12">elements it defines in Python</a> allow you to specify the HTMx tags (such as <code><a href="https://htmx.org/docs/">hx-post</a></code>) right in Python, and FastHTML generates the correctly decorated HTML for you.</p><p>Note: <a href="https://htmx.org/">HTMx</a> has recently (2024) released HTMx version 2. Thankfully FastHTML already uses HTMx version 2.</p><h2 id="getting-started-with-fasthtml-%F0%9F%8E%A5-tutorial-notes"><br>Getting started with FastHTML &#x1F3A5; tutorial notes</h2><p>As I followed the FastHTML tutorial video, I took notes on errors I encountered and document the various error <em>you</em> may also see with helpers to resolve them. These can be helpful when thown unfamiliar errors within a new codebase.</p><p>Error&apos;s you may see following &apos;Getting started with FastHTML&apos; video by Jeremy Howard:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.youtube.com/embed/Auqrm7WFc0I"><div class="kg-bookmark-content"><div class="kg-bookmark-title">YouTube</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.youtube.com/favicon.ico" alt="FastHTML getting started &amp; comparison with Flask"></div></div></a></figure><h6 id="not-knowing-that-url-arguments-must-be-typed-in-fasthtml">Not knowing that url arguments must be typed in FastHTML</h6><pre><code>if target_id: kwargs[&apos;hx_target&apos;] = &apos;#&apos;+target_id
                                        ~~~^~~~~~~~~~
TypeError: can only concatenate str (not &quot;int&quot;) to str</code></pre><p>The above is a <a href="https://htmx.org/">HTMx</a> error telling you you&apos;ve past an <code>Integer</code> for <code>target_id</code> rather than a string:</p><p>Before fix:</p><pre><code>def render(todo):
    tid = todo.id
    toggle = A(&apos;Toggle&apos;, hx_get=f&apos;/toggle/{todo.id}&apos;, target_id=tid)
    return Li(toggle, todo.title, id=tid)</code></pre><p>Code after fix:</p><pre><code>def render(todo):
    tid = f&apos;todo-{todo.id}&apos;
    toggle = A(&apos;Toggle&apos;, hx_get=f&apos;/toggle/{todo.id}&apos;, target_id=tid)
    return Li(toggle, todo.title, id=tid)</code></pre><blockquote>You could also simply do <code>target_id=str(tid)</code> but then your HTML id&apos;s would risk not being unique. The prefix <code>todo-</code> results in <code>id=&quot;todo-1</code>&quot;, <code>id=&quot;todo-2</code>&quot; etc. If you had other elements on a page (e.g. a list of people) you&apos;d want to avoid using only the number.</blockquote><h6 id="you-see-fastlitekwpy-notfounderror">You see &quot;fastlite/kw.py NotFoundError&quot;</h6><h5></h5><p>If you&apos;re used to Flask, you&apos;ll know that route arguments don&apos;t<em> require</em> type signatures. Though not required in Starlette framework&apos;s <a href="https://www.starlette.io/routing/#:~:text=Starlette%27s%20HTTPEndpoint.-,Path%20Parameters,-Paths%20can%20use">routing system</a> (which FastHTML is built upon), they appear required in FastHTML. If you&apos;re curious here&apos;s a <a href="https://github.com/Subscribie/subscribie-deployer/blob/19c578b371381bc7a42a47df95b0e17c4176ec5e/main.py#L432-L435">small example using Starlette&apos;s routing system</a> without using FastHTML on-top of Starlette.</p><p>In the FastHTML tutorial, the root cause of the <code>fastlite/kw.py NotFoundError</code> mistake* is helpfully made on the &quot;`/toggle/id`&quot; tid endpoint, which is is <code>None</code> when clicking a TODO list item. <br><br>&gt; It&apos;s <em>helpful</em> in the sense these mistakes are <em>kept</em> in tutorials for learning- I would&apos;t be surprised if Jeremy makes these on purpose- he&apos;s an outstanding and well-known teacher).<br><br>Example invalid route: </p><pre><code>@rt(&apos;/toggle/{tid}&apos;)
def get(tid):  # noqa: F811
    todo = todos[tid]
    todo.done = not todo.done
    todo.update(todo)
    return todo</code></pre><p>Example corrected route with <code>:int</code> added for type information:</p><figure class="kg-card kg-code-card"><pre><code>@rt(&apos;/toggle/{tid}&apos;)
def get(tid:int):  # noqa: F811
    todo = todos[tid]
    todo.done = not todo.done
    todo.update(todo)
    return todo</code></pre><figcaption>Note the addition of <code>:int</code> to the <code>def get</code> method</figcaption></figure><h4 id="you-see-attributeerror-items-object-has-no-attribute-update">You see <code>AttributeError: &apos;Items&apos; object has no attribute &apos;update&apos;</code></h4><p>If like me you manually type things out when learning from a tutorial, you may trip up on the following mistake (wrong):</p><pre><code>@rt(&apos;/toggle/{tid}&apos;)
def get(tid:int):  # noqa: F811
    todo = todos[tid]
    todo.done = not todo.done
    todo.update(todo)
    return todo</code></pre><p>vs below (corrected)</p><pre><code>@rt(&apos;/toggle/{tid}&apos;)
def get(tid:int):  # noqa: F811
    todo = todos[tid]
    todo.done = not todo.done
    todos.update(todo)
    return todo
</code></pre><p>This is a chance to inspect the database helpers FastHTML has bundled out of the box. Let&apos;s dig into the type of <code>todos</code> by putting a <code>breakpoint()</code> after <code>todo.done</code> and inspect <code>todos</code> type:</p><pre><code>todos.__class__  
&lt;class &apos;sqlite_minutils.db.Table&apos;&gt;</code></pre><p>Above we can see FastHTML is using the <a href="https://github.com/AnswerDotAI/sqlite-minutils"><code>sqlite-minutils</code></a> python package which appears to provide a simple helpful wrapper around common SQLite operations within Python (<a href="https://en.wikipedia.org/wiki/Syntactic_sugar">syntactic sugar)</a>. Makes me nervous when I see such projects being so new (2 months at the time of writing, but less nervous when considering the people behind such projects, however it&apos;s a hard(?) fork of <code>sqlite-utils</code> which has a long (over 4 years) history and venerable provenance from <a href="https://simonwillison.net/about/">Simon Willison</a> (co-creator of <a href="https://www.djangoproject.com/">Django</a>). Doing things like this can create a sunk cost maintenance burden in the future needing to back-port <a href="https://github.com/AnswerDotAI/sqlite-minutils/commit/5855737608069f017f0732f992d3d8a15dd7e197">improvements</a> / features which may come from either side. </p><h3 id="final-thoughts-after-quick-start-with-fasthtml">Final thoughts after quick-start with FastHTML</h3><p>What a breeze, what a lovely coming together of web technologies!<br><br>I&apos;m left with the thirst to get good patterns nailed/documented for:</p><!--kg-card-begin: markdown--><ul>
<li>Database migrations (I&apos;m used to using <a href="https://flask-migrate.readthedocs.io/en/latest/">Flask-Migrate</a> by <a href="https://blog.miguelgrinberg.com/">Miguel Grinberg</a> which is a wrapper for <a href="https://www.sqlalchemy.org/">SQLAlchemy&apos;s</a> <a href="https://alembic.sqlalchemy.org/en/latest/">Alembic</a>- a <strong>fantastic</strong> database schema migration)
<ul>
<li>Integration with SQLAlchemy generally. I&apos;m still learning to love FastHTML&apos;s (very?) opinionated way to model databases- new commers will get used to tearing down their database and aren&apos;t (yet) presented with patterns to handel schema migration. Documented patterns for schema migrations is one thing I&apos;m looking for to make day two operations (production) a thing. It&apos;s early days (and open source welcoming contributions..)</li>
</ul>
</li>
<li>A clearer understanding of how to handle multiple databases. In the tutorial it&apos;s not clear to be how multiple databases are modeled (esecially when multiple collumns get added as arguments to <code>fast_app</code>. The tutorial, by design is simple and may be a case of <a href="https://en.wikipedia.org/wiki/RTFM">RTFM</a>)</li>
<li>Does FastHTML have an equivalent to Flask&apos;s <code>url_for</code>? Yes. The docs don&apos;t seem to reference that. <a href="https://www.starlette.io/routing/#:~:text=%3Droutes">Starlette does</a>-,Reverse%20URL%20lookups,-You%27ll%20often%20want) so it&apos;s a matter of documentation. I was concerned about when paths change and having to update all those strings (this goes against the leaning toward types FastHTML has with it&apos;s elements)</li>
<li>and now just getting carried away / hungry for docs on
<ul>
<li>Integrating translations (i18n/gettext)</li>
<li>JSON endpoints examples - I&apos;m loving <code>htmx</code> as much as the next person, but what are the patterns for this? The htmx author has some <a href="https://www.reddit.com/r/htmx/comments/ykzy9t/comment/iv0vtvz/?utm_source=share&amp;utm_medium=web3x&amp;utm_name=web3xcss&amp;utm_term=1&amp;utm_content=share_button">references</a> for exactly this already</li>
</ul>
</li>
</ul>
<!--kg-card-end: markdown--><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.linkedin.com/in/christopher-simpson-25288525/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Christopher Simpson - Amazon Web Services (AWS) | LinkedIn</div><div class="kg-bookmark-description">Experienced Director with a demonstrated history of working in the information technology&#x2026; &#xB7; Experience: Amazon Web Services (AWS) &#xB7; Education: Northumbria University &#xB7; Location: Newcastle Upon Tyne &#xB7; 500+ connections on LinkedIn. View Christopher Simpson&#x2019;s profile on LinkedIn, a professional commun&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://static.licdn.com/aero-v1/sc/h/al2o9zrvru7aqj8e1x2rzsrca" alt="FastHTML getting started &amp; comparison with Flask"><span class="kg-bookmark-author">LinkedIn</span><span class="kg-bookmark-publisher">Christopher Simpson</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://static.licdn.com/aero-v1/sc/h/1c5u578iilxfi4m4dvc4q810q" alt="FastHTML getting started &amp; comparison with Flask"></div></a></figure><p> </p>]]></content:encoded></item><item><title><![CDATA[Deleting files "Cannot be removed because it is not empty" Error (Solved)]]></title><description><![CDATA[<p>Struggling to delete a persistent file? We were facing the same problem!</p><p>In our case, we encountered this issue while working with <strong>WSL (Windows Subsystem for Linux) </strong>and <strong>Python</strong> and we wanted to delete a folder.</p><p>If you&apos;re here just for the solution, here&apos;s what you</p>]]></description><link>https://blog.karmacomputing.co.uk/windows-rm-cannot-be-removed-because-it-is-not-empty/</link><guid isPermaLink="false">64f6e35db93427b5f9b20201</guid><category><![CDATA[debugging]]></category><category><![CDATA[programming]]></category><dc:creator><![CDATA[Joseph Blessing]]></dc:creator><pubDate>Wed, 06 Sep 2023 05:09:28 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2023/09/crop-person-using-laptop_1161-185.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.karmacomputing.co.uk/content/images/2023/09/crop-person-using-laptop_1161-185.jpg" alt="Deleting files &quot;Cannot be removed because it is not empty&quot; Error (Solved)"><p>Struggling to delete a persistent file? We were facing the same problem!</p><p>In our case, we encountered this issue while working with <strong>WSL (Windows Subsystem for Linux) </strong>and <strong>Python</strong> and we wanted to delete a folder.</p><p>If you&apos;re here just for the solution, here&apos;s what you can do: </p><p>Step 1: Open Task Manager.</p><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image-9.png" class="kg-image" alt="Deleting files &quot;Cannot be removed because it is not empty&quot; Error (Solved)" loading="lazy" width="1129" height="1012" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/09/image-9.png 600w, https://blog.karmacomputing.co.uk/content/images/size/w1000/2023/09/image-9.png 1000w, https://blog.karmacomputing.co.uk/content/images/2023/09/image-9.png 1129w" sizes="(min-width: 720px) 720px"></figure><p>Step 2: Find Python and End Task, then proceed to delete the troublesome files.</p><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image-8.png" class="kg-image" alt="Deleting files &quot;Cannot be removed because it is not empty&quot; Error (Solved)" loading="lazy" width="1128" height="1012" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/09/image-8.png 600w, https://blog.karmacomputing.co.uk/content/images/size/w1000/2023/09/image-8.png 1000w, https://blog.karmacomputing.co.uk/content/images/2023/09/image-8.png 1128w" sizes="(min-width: 720px) 720px"></figure><h2 id="why-did-this-happen-and-what-problems-did-we-face">Why did this happen and what problems did we face?</h2><p>So as stated before, we were working with <strong>WSL (Windows Subsystem for Linux)</strong> on setting up an application locally. </p><p><strong>Method 1: </strong>We initially attempted to delete the file normally in Windows Explorer, only to be met with a message indicating that the files were in use by another application.</p><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image-11.png" class="kg-image" alt="Deleting files &quot;Cannot be removed because it is not empty&quot; Error (Solved)" loading="lazy" width="997" height="559" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/09/image-11.png 600w, https://blog.karmacomputing.co.uk/content/images/2023/09/image-11.png 997w" sizes="(min-width: 720px) 720px"></figure><p>Method 2: We decided to take a bit more assertive approach to delete the file using Comand Prompt. We tried the following commands:</p><!--kg-card-begin: markdown--><pre><code>rm C:\Users\User1\software -r -force
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><pre><code>Remove-Item C:\Users\User1\software\venv -Recurse
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><pre><code>Get-ChildItem C:\Users\User1\software\venv  -Recurse | Remove-Item -Force
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><pre><code>Remove-Item C:\Users\User1\software\venv
</code></pre>
<!--kg-card-end: markdown--><p>These commands are used to delete files from the computer or force to delete the files and their subfiles and folders.</p><p>However, our attempts were met with the following errors:</p><!--kg-card-begin: markdown--><pre><code>The file &#x2018;FileName&#x2019; cannot be removed because it is not empty
</code></pre>
<!--kg-card-end: markdown--><p>and</p><!--kg-card-begin: markdown--><pre><code>+ CategoryInfo          : PermissionDenied: (file:FileInfo) [Remove-Item], UnauthorizedAccessException
</code></pre>
<!--kg-card-end: markdown--><p>To our relief, the solution to solve this was very simple. Since we were working on an application that made use of Python, the files were being used by Python.exe. By killing the Python.exe in the Task Manager, we were able to delete the files without any issues! Sometimes the hardest problems require the simplest of solutions ;)</p>]]></content:encoded></item><item><title><![CDATA[Installing WireGuard VPN on Windows]]></title><description><![CDATA[<h3 id="step-1-wireguard-download-the-wireguard-windows-installer">Step 1: WireGuard download the Wireguard <a href="https://www.wireguard.com/install/#windows-7-81-10-11-2008r2-2012r2-2016-2019-2022">Windows installer</a></h3><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image.png" class="kg-image" alt loading="lazy" width="1703" height="794" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/09/image.png 600w, https://blog.karmacomputing.co.uk/content/images/size/w1000/2023/09/image.png 1000w, https://blog.karmacomputing.co.uk/content/images/size/w1600/2023/09/image.png 1600w, https://blog.karmacomputing.co.uk/content/images/2023/09/image.png 1703w" sizes="(min-width: 720px) 720px"></figure><h3 id="step-2-run-the-installation-file-and-the-installation-should-automatically-complete">Step 2: Run the installation file and the installation should automatically complete</h3><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image-1.png" class="kg-image" alt loading="lazy" width="732" height="282" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/09/image-1.png 600w, https://blog.karmacomputing.co.uk/content/images/2023/09/image-1.png 732w" sizes="(min-width: 720px) 720px"></figure><h3 id="step-3-once-the-wireguard-client-opens-upon-installation-youll-need-to-add-tunnels-to-start-using-wireguard">Step 3: Once the WireGuard client opens upon installation, you&apos;ll need to add tunnels to start using WireGuard.</h3><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text"><strong>What are tunnels? </strong><br>They are used to create a</div></div>]]></description><link>https://blog.karmacomputing.co.uk/install-wireguard-vpn-on-windows/</link><guid isPermaLink="false">64f7f8abb93427b5f9b2024b</guid><category><![CDATA[open source]]></category><category><![CDATA[Sysadmin]]></category><category><![CDATA[internet]]></category><category><![CDATA[devops]]></category><dc:creator><![CDATA[Joseph Blessing]]></dc:creator><pubDate>Wed, 06 Sep 2023 05:09:23 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2023/09/standard-quality-control-collage-concept.jpg" medium="image"/><content:encoded><![CDATA[<h3 id="step-1-wireguard-download-the-wireguard-windows-installer">Step 1: WireGuard download the Wireguard <a href="https://www.wireguard.com/install/#windows-7-81-10-11-2008r2-2012r2-2016-2019-2022">Windows installer</a></h3><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image.png" class="kg-image" alt="Installing WireGuard VPN on Windows" loading="lazy" width="1703" height="794" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/09/image.png 600w, https://blog.karmacomputing.co.uk/content/images/size/w1000/2023/09/image.png 1000w, https://blog.karmacomputing.co.uk/content/images/size/w1600/2023/09/image.png 1600w, https://blog.karmacomputing.co.uk/content/images/2023/09/image.png 1703w" sizes="(min-width: 720px) 720px"></figure><h3 id="step-2-run-the-installation-file-and-the-installation-should-automatically-complete">Step 2: Run the installation file and the installation should automatically complete</h3><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image-1.png" class="kg-image" alt="Installing WireGuard VPN on Windows" loading="lazy" width="732" height="282" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/09/image-1.png 600w, https://blog.karmacomputing.co.uk/content/images/2023/09/image-1.png 732w" sizes="(min-width: 720px) 720px"></figure><h3 id="step-3-once-the-wireguard-client-opens-upon-installation-youll-need-to-add-tunnels-to-start-using-wireguard">Step 3: Once the WireGuard client opens upon installation, you&apos;ll need to add tunnels to start using WireGuard.</h3><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text"><strong>What are tunnels? </strong><br>They are used to create a virtual network interface that you can use to route traffic between two endpoints. When you configure both endpoints, you establish a connection.</div></div><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image-2.png" class="kg-image" alt="Installing WireGuard VPN on Windows" loading="lazy" width="911" height="726" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/09/image-2.png 600w, https://blog.karmacomputing.co.uk/content/images/2023/09/image-2.png 911w" sizes="(min-width: 720px) 720px"></figure><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/standard-quality-control-collage-concept.jpg" alt="Installing WireGuard VPN on Windows"><p>There are two ways you can approach this:</p><ol><li>Importing a tunnel file</li><li>Create a tunnel manually</li></ol><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image-3.png" class="kg-image" alt="Installing WireGuard VPN on Windows" loading="lazy" width="435" height="307"></figure><h4 id="import-a-tunnel-you-can-import-a-tunnel-file-in-the-format-of-zip-or-conf">Import a tunnel: You can import a tunnel file in the format of .zip or .conf</h4><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image-5.png" class="kg-image" alt="Installing WireGuard VPN on Windows" loading="lazy" width="285" height="138"></figure><h4 id="create-a-tunnel-manually-here-you-start-from-scratch-and-enter-the-configuration-you-would-like-to-have-for-your-tunnel">Create a tunnel manually: Here you start from scratch and enter the configuration you would like to have for your tunnel</h4><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image-6.png" class="kg-image" alt="Installing WireGuard VPN on Windows" loading="lazy" width="1115" height="884" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/09/image-6.png 600w, https://blog.karmacomputing.co.uk/content/images/size/w1000/2023/09/image-6.png 1000w, https://blog.karmacomputing.co.uk/content/images/2023/09/image-6.png 1115w" sizes="(min-width: 720px) 720px"></figure><h3 id="step-4-make-sure-to-enter-the-tunnel-information-in-the-format-below">Step 4: Make sure to enter the tunnel information in the format below:</h3><!--kg-card-begin: markdown--><pre><code>[Interface]
PrivateKey = 
Address = 
DNS =

[Peer]
PublicKey = 
AllowedIPs = 
Endpoint =
</code></pre>
<!--kg-card-end: markdown--><p>Feel free to add more information if needed to your tunnel then click Save</p><p>Step 5: Now, click &quot;Activate&quot; to enable your VPN.</p><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/09/image-7.png" class="kg-image" alt="Installing WireGuard VPN on Windows" loading="lazy" width="851" height="672" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/09/image-7.png 600w, https://blog.karmacomputing.co.uk/content/images/2023/09/image-7.png 851w" sizes="(min-width: 720px) 720px"></figure><p>Congratulations! You&apos;ve now successfully installed and configured your WireGuard VPN on Windows.</p>]]></content:encoded></item><item><title><![CDATA[Windows containers how to...not?]]></title><description><![CDATA[<h2 id="things-to-know-about-windows-containers">Things to know about Windows Containers</h2><blockquote>This started as an initial research into Windows Containers. My initial impression was not fantastic, left wanting.</blockquote><!--kg-card-begin: markdown--><ul>
<li>&quot;Windows requires the host OS version to match the container OS version&quot; (<a href="https://hub.docker.com/_/microsoft-windows-base-os-images">src</a>)
<ul>
<li>This is in stark constrast compared to Linux containers, where you can</li></ul></li></ul>]]></description><link>https://blog.karmacomputing.co.uk/windows-containers-how-to/</link><guid isPermaLink="false">647e37cbb93427b5f9b1ffa4</guid><category><![CDATA[devops]]></category><category><![CDATA[open source]]></category><category><![CDATA[security]]></category><category><![CDATA[Sysadmin]]></category><category><![CDATA[docker]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Mon, 05 Jun 2023 21:50:43 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2023/06/windows-containers-how-to-not.jpg" medium="image"/><content:encoded><![CDATA[<h2 id="things-to-know-about-windows-containers">Things to know about Windows Containers</h2><blockquote>This started as an initial research into Windows Containers. My initial impression was not fantastic, left wanting.</blockquote><!--kg-card-begin: markdown--><ul>
<li>&quot;Windows requires the host OS version to match the container OS version&quot; (<a href="https://hub.docker.com/_/microsoft-windows-base-os-images">src</a>)
<ul>
<li>This is in stark constrast compared to Linux containers, where you can trivially, swap out a Debian based image with a lighter, tighter alpine based image, or even change languages as needs evole (saving you time &amp; money due to lower resource costs, <em>and</em> speed increases)</li>
<li>The above is also a small lie, you <em>can</em> &quot;use Hyper-V isolation to run older containers on new host builds&quot; (<a href="https://hub.docker.com/_/microsoft-windows-base-os-images">src</a>)</li>
<li>If that sounds finicky, it is</li>
</ul>
</li>
<li>The default entrypoint for each Windows base OS image is a console, either cmd.exe or PowerShell. (<a href="https://hub.docker.com/_/microsoft-windows-base-os-images">src</a>)</li>
<li>The &quot;latest&quot; tag isn&apos;t a thing for Windows container builds. You&apos;ll find this weird if you&apos;re familiar with the container ecosystem because it breaks the established convention of the latest build of a container image being tagged with <code>latest</code></li>
<li>It&apos;s a mess don&apos;t bother- take the plunge and use Linux containers, and a container orchestrator like Kubernetes, Openshift, and pay for training and support to up-skill teams. Unless you have a massive .NET estate (perhaos). Read on for reasoning.</li>
</ul>
<h1 id="do-i-need-a-licence-for-my-windows-containers">Do I need a licence for my Windows <em>containers</em>?</h1>
<img src="https://blog.karmacomputing.co.uk/content/images/2023/06/windows-containers-how-to-not.jpg" alt="Windows containers how to...not?"><p>Not for the containers. You <em>do</em> need a license for the host on which they run, though- and that host has to be Windows.</p>
<p>The warning is quite stern, reminiscent of the familiar shouty MIT licence which fondly shreeks: &quot;THE SOFTWARE IS PROVIDED &#x201C;AS IS&#x201D;, WITHOUT WARRANTY OF ANY KIND&quot; (<a href="https://drewdevault.com/2021/06/14/Provided-as-is-without-warranty.html">src</a>).</p>
<p>With Microsoft, a different take- a stern warning to not run Windows containers without a licence:</p>
<blockquote>
<p>&quot;You may not use the Container Image if you do not have a corresponding version and edition of the Host License&quot; (<a href="https://learn.microsoft.com/en-us/virtualization/windowscontainers/images-eula">src</a> - Microsoft)</p>
</blockquote>
<p>So you&apos;d be forgiven for thinking getting the license puts you in a better place than the &quot;NO WARRANTY OF ANY KIND&quot; with Linux containers- but no, even with your shiny Windows licence, the conditions are still as follows:</p>
<blockquote>
<p>&quot;The software is licensed &#x201C;as-is.&#x201D; You bear the risk of using it. Microsoft gives no express warranties, guarantees or conditions.&quot;The software is licensed &#x201C;as-is.&#x201D; You bear the risk of using it. Microsoft gives no express warranties, guarantees or conditions.&quot; (<a href="https://support.microsoft.com/en-us/windows/microsoft-software-license-terms-e26eedad-97a2-5250-2670-aad156b654bd">src</a> - Microsoft)</p>
</blockquote>
<p>So it&apos;s not readily clear what the value-add benefits are to running containers under Windows yet, since we&apos;ve established flexibility and ease are not one of them.</p>
<p>It&apos;s easy to simply <em>not see</em> these very real issues if you&apos;re on say, the Microsoft Partner Program which gets you all these &apos;permissions slips&apos; with no warranty to run containers for a few hundered bucks. But since the ambiguity around container security (how to I update my containers) is so vague, why would you walk the path?</p>
<blockquote>
<p>&quot;Microsoft has delayed the scheduled end of support and servicing dates for a number of products to help people and organisations focus their attention on retaining business continuity.&quot; - <a href="https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/base-image-lifecycle">Microsoft Base image servicing life-cycles</a>, April 14th 2020</p>
</blockquote>
<p>It&apos;s very hard to see Windows containers getting updated at a regular cadence (aka &apos;SecOps&apos;) which is practically a solved problem in the Linux world (read: <a href="https://www.oreilly.com/library/view/container-security/9781492056690/">Container Security, by Liz Rice</a>) and you&apos;ll take onboard how to pull, update/upgrade/patch container images and <em>automate</em> that good security process as part of every release- it&apos;s so trivial now it&apos;s boring. The same simply isn&apos;t the case, sadly, for Windows containers in their current form. The &quot;Semi-Annual Channel is a twice-per-year feature update release&quot; simply doesn&apos;t cut it for remaining competitive, whilst also having piece of mind for security.</p>
<h1 id="question-if-you-even-need-windows-containers-at-all">Question if you even need Windows containers at all</h1>
<p>If you&apos;re embarking on a large modernisation project, realising that the industry is changing around you- and your organisations technology choices are slowing down your competitiveness, then <em>resist the urge to stay with the familiar</em>. You&apos;re already considering the change. Take a hard look at your foundations (Windows) and ask the hard questions.</p>
<p>That said, perhaps you have an extremely large, successfully and happy .net code base and you&apos;re looking to automate further your build and release process. <em>Perhaps</em> there&apos;s room there. Though, if you do have such a significant .NET application(s), by the time your using the official Windows &quot;Server&quot; container image (which is 11.2GB), what <em>are</em> the advantages over creating a VM? It&apos;s not clear within the Windows ecosystem at leas- read on to deliberate why.</p>
<h1 id="are-windows-containers-even-containers">Are Windows containers even containers?</h1>
<p>No. They are not. Linux containers, are an ensemble of Linux kernel constructs (namespaces, croups) which <em>share the host operating kernel</em> to create the illusion of isolation between processes, leaning on namespaces. If that sounds a lot, look at the artwork by <a href="https://jvns.ca/blog/2020/04/27/new-zine-how-containers-work/#:~:text=It%20turns%20out%20that%20containers,bunch%20of%20confusing%20edge%20cases.">Julia Evans &apos;How Containers Work&apos;</a> :</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://jvns.ca/blog/2020/04/27/new-zine-how-containers-work/#:~:text=It%20turns%20out%20that%20containers,bunch%20of%20confusing%20edge%20cases."><div class="kg-bookmark-content"><div class="kg-bookmark-title">New zine: How Containers Work!</div><div class="kg-bookmark-description">New zine: How Containers Work!</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://jvns.ca/favicon.ico" alt="Windows containers how to...not?"><span class="kg-bookmark-author">Julia Evans</span><span class="kg-bookmark-publisher">Julia Evans</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://jvns.ca/images/containers-cover.jpg" alt="Windows containers how to...not?"></div></a></figure><p>The result of Linux containers, is you get a semi isolated way to run useful programs on the same hardware with <em>strong-enough</em> promises around isolation for most people. By &apos;most people&apos; this does not include public cloud providers, where, perhaps surprisingly your containers are, still, in-fact vac-wrapped within the complete isolation of a Virtual Machine. This is in comparison to arguably harder isolation guarantees which are found in operating systems such as <a href="https://illumos.org/man/7/zones">Illumos Zones</a>, and <a href="bhyve">FreeBSD bhyve</a>. Regardless, these <code>cgroups</code>, <code>namespaces</code> and the &quot;Open Container Image layout specification&quot; (<a href="https://github.com/opencontainers/image-spec">OCI</a>) primitives allow us to reason about these programs as &apos;containers&apos;. </p><p>Within the Linux container ecosystem, the above results in:</p><!--kg-card-begin: markdown--><ul>
<li>Small, portable container images (as small as a few megabytes)
<ul>
<li>In security, there&apos;s the concept of &apos;reducing the attack surface&apos; (less code, less things to go wrong- ship only what you need, and ideally make it imutable)</li>
<li>If it&apos;s not in your container, you don&apos;t need to patch it, this is in contrast to the VM approach where, you have everything &amp; the kitchen sink whether you want it or not</li>
<li>...you&apos;re paying for all that too, by the way- in storage, ingres/egres , attack surface, hard to reproduce bugs etc</li>
</ul>
</li>
<li>Which can be kept up to date (patched)</li>
<li>Unencumbered (licencing restrictions)</li>
<li>Portable- the fact you can run a Linux container image on any host operating system easily  (including Windows, bizarrely) puts the flexibility of the approach head over heals of the Windows containers alternative</li>
<li>Code in any language (create python, Rust - even .net) Linux containers</li>
</ul>
<!--kg-card-end: markdown--><p>Windows containers don&apos;t take that approach, colour is added to the ecosystem with an <em>interesting</em> approach.</p><blockquote>&quot;Windows offers four container base images that users can build from. Each base image is a different type of the Windows or Windows Server operating system, has a different on-disk footprint, and has a different set of the Windows API set.&quot;<br><a href="https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/container-base-images">- Container Base Images, Microsoft 2023</a></blockquote><p>By contrast, these images range from 295MB (Nano Server) to &gt; 11GB (the &apos;Server base&apos; container image&apos;). These sizes vary of course, as updates and patches are released. See &quot;Nano Server x Server Core x Server - Which base image is the right one for you?&quot; - <a href="https://techcommunity.microsoft.com/t5/containers/nano-server-x-server-core-x-server-which-base-image-is-the-right/ba-p/2835785#:~:text=Once%20pulled%20and%20extracted%2C%20the,has%20around%20290MB%20in%20size.">tech community, Microsoft 2021</a>.<br><br>The venerable Microsoft has an excellent track record in maintaining backward compatibility, and perhaps this is why it&apos;s less trivial to introduce isolation primitives into Windows which Linux and other *Nix systems benefit from making the &apos;container&apos; abstraction easier to create- they started out as time sharing operating systems, <em>expecting</em> multiple but separate users. This is in stark contrast to Windows which had been <em><strong>single user </strong></em>since it&apos;s DOS days, and only <em>eventually</em> was the concept of multi-user added to the operating system- on-top). When you pile so much on top, the straw breaks the camels back. In this case the back is ease of use and an addressable market. That said, Linus famously stated &quot;<a href="https://linuxreviews.org/WE_DO_NOT_BREAK_USERSPACE">We don&apos;t break userspace</a>&quot;, but- to it&apos;s history does not suffer from the fundamental disconnect in where this systems began (time sharing vs single user systems).</p><h2 id="links-references">Links &amp; References</h2><ul><li><a href="https://jvns.ca/blog/2020/04/27/new-zine-how-containers-work/#:~:text=It%20turns%20out%20that%20containers,bunch%20of%20confusing%20edge%20cases.">Julia Evans &apos;How Containers Work&apos;</a></li><li><a href="https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/container-base-images">https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/container-base-images</a></li><li>https://hub.docker.com/_/microsoft-windows-base-os-images</li><li><a href="https://linuxreviews.org/WE_DO_NOT_BREAK_USERSPACE">We don&apos;t break userspace</a><br></li></ul>]]></content:encoded></item><item><title><![CDATA[How to Create a Table of Contents on Ghost]]></title><description><![CDATA[You know what's scary? Ghosts. You know what's even scarier? Not having a table of contents on your blog posts on Ghost! That's why I'm going to show you how to make one in just a few easy steps. No coding required, no ghost hunting needed. Just follow me and you'll be fine.
]]></description><link>https://blog.karmacomputing.co.uk/ghost-create-an-interactive-contant-table/</link><guid isPermaLink="false">6479e0e1b93427b5f9b1fece</guid><category><![CDATA[Blog]]></category><category><![CDATA[content marketing]]></category><dc:creator><![CDATA[Joseph Blessing]]></dc:creator><pubDate>Mon, 05 Jun 2023 05:51:34 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2023/06/2736890_12168.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card kg-toggle-card" data-kg-toggle-state="close"><div class="kg-toggle-heading"><h4 class="kg-toggle-heading-text">Table of Contents</h4><button class="kg-toggle-card-icon"><svg id="Regular" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path class="cls-1" d="M23.25,7.311,12.53,18.03a.749.749,0,0,1-1.06,0L.75,7.311"/></svg></button></div><div class="kg-toggle-content"><img src="https://blog.karmacomputing.co.uk/content/images/2023/06/2736890_12168.png" alt="How to Create a Table of Contents on Ghost"><p><a href="#how-to-create-a-table-of-contents-on-ghost">How to Create a Table of Contents on Ghost</a></p><p><a href="steps-to-make-a-table-of-contents-for-ghost">Steps to Make a Table of Contents for Ghost</a><br></p></div></div><h2 id="how-to-create-a-table-of-contents-on-ghost"><strong>How to Create a Table of Contents on Ghost</strong></h2><p>If you&apos;re like me, you love reading stuff on the internet. But sometimes you don&apos;t have time to read everything, or you just want to skip to the juicy bits. That&apos;s why a table of contents is awesome. It lets you jump to any section of an article with a click of a button.</p><p>Wondering how you make one for your own for your blog on Ghost without coding skills? Well, wonder no more, because I&apos;m here to share with you my secret trick that made it possible for me! Trust me, it&apos;s easier than you think!</p><h2 id="steps-to-make-a-table-of-contents-for-ghost">Steps to Make a Table of Contents for Ghost</h2><p><strong>Step 1: </strong>Write your article and insert a<strong> Toggle element </strong>where you want your table of contents to be.</p><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/06/image.png" class="kg-image" alt="How to Create a Table of Contents on Ghost" loading="lazy" width="1281" height="488" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/06/image.png 600w, https://blog.karmacomputing.co.uk/content/images/size/w1000/2023/06/image.png 1000w, https://blog.karmacomputing.co.uk/content/images/2023/06/image.png 1281w" sizes="(min-width: 720px) 720px"></figure><p><strong>Step 2: </strong>Copy and paste all your headings into the Toggle element.</p><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/06/image-6.png" class="kg-image" alt="How to Create a Table of Contents on Ghost" loading="lazy" width="1113" height="606" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/06/image-6.png 600w, https://blog.karmacomputing.co.uk/content/images/size/w1000/2023/06/image-6.png 1000w, https://blog.karmacomputing.co.uk/content/images/2023/06/image-6.png 1113w" sizes="(min-width: 720px) 720px"></figure><p><strong>Step 3: </strong>In the Toggle element, highlight a heading and press the link icon to create a hyperlink for it.</p><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/06/image-1.png" class="kg-image" alt="How to Create a Table of Contents on Ghost" loading="lazy" width="575" height="326"></figure><p><strong>Step 4: </strong>Type a <strong>hash (#)</strong> followed by the heading with <strong>dashes (-)</strong> instead of spaces. A comparable example is the slug portion of a URL.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">For example, if your heading is <strong>&quot;Why I Love Cats&quot;</strong>, type <strong>&quot;#why-i-love-cats&quot;.</strong></div></div><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/06/image-4.png" class="kg-image" alt="How to Create a Table of Contents on Ghost" loading="lazy" width="601" height="189" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/06/image-4.png 600w, https://blog.karmacomputing.co.uk/content/images/2023/06/image-4.png 601w"></figure><p>Do this for all your headings and voila! You have a table of contents that works like magic. Enjoy!</p><figure class="kg-card kg-image-card"><img src="https://blog.karmacomputing.co.uk/content/images/2023/06/image-7.png" class="kg-image" alt="How to Create a Table of Contents on Ghost" loading="lazy" width="1077" height="533" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/06/image-7.png 600w, https://blog.karmacomputing.co.uk/content/images/size/w1000/2023/06/image-7.png 1000w, https://blog.karmacomputing.co.uk/content/images/2023/06/image-7.png 1077w" sizes="(min-width: 720px) 720px"></figure><p>Subscribe if you want more helpful Tips and Guides from us, we&apos;ll be sure to make it worth your while. &#x1F604;</p>]]></content:encoded></item><item><title><![CDATA[If I want to get a website set up and some SEO done, what sort of figures would I be looking at?]]></title><description><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.karmacomputing.co.uk/content/images/2023/05/image.png" class="kg-image" alt loading="lazy" width="625" height="324" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/05/image.png 600w, https://blog.karmacomputing.co.uk/content/images/2023/05/image.png 625w"><figcaption>Not really.</figcaption></figure><blockquote>&quot;for reals though, if it&apos;s just a simple one page website, and to stick some keywords into google&quot;</blockquote><p></p><p>...</p><blockquote>&quot;Without more information I&apos;d question why not use Squarespace, Wix, WordPress? They are all adequate. We also sell<a href="https://karmacomputing.co.uk/page/small-business-web-hosting"> small business web hosting with</a></blockquote>]]></description><link>https://blog.karmacomputing.co.uk/if-i-want-to-get-a-website-set-up-and-some-seo-done-what-sort-of-figures-would-i-be-looking-at/</link><guid isPermaLink="false">64775cdfb93427b5f9b1fe92</guid><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Wed, 31 May 2023 14:50:24 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2023/05/i-web-to-setup-a-basic-website-how-do-i.jpg" medium="image"/><content:encoded><![CDATA[<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.karmacomputing.co.uk/content/images/2023/05/image.png" class="kg-image" alt="If I want to get a website set up and some SEO done, what sort of figures would I be looking at?" loading="lazy" width="625" height="324" srcset="https://blog.karmacomputing.co.uk/content/images/size/w600/2023/05/image.png 600w, https://blog.karmacomputing.co.uk/content/images/2023/05/image.png 625w"><figcaption>Not really.</figcaption></figure><blockquote>&quot;for reals though, if it&apos;s just a simple one page website, and to stick some keywords into google&quot;</blockquote><img src="https://blog.karmacomputing.co.uk/content/images/2023/05/i-web-to-setup-a-basic-website-how-do-i.jpg" alt="If I want to get a website set up and some SEO done, what sort of figures would I be looking at?"><p></p><p>...</p><blockquote>&quot;Without more information I&apos;d question why not use Squarespace, Wix, WordPress? They are all adequate. We also sell<a href="https://karmacomputing.co.uk/page/small-business-web-hosting"> small business web hosting with suppor</a>t.</blockquote><p>...</p><blockquote>&quot;Oh is it that easy?&quot;</blockquote><p>...</p><blockquote>&quot;Depends what &quot;it&quot; is &#x1F642;. A brochure website very simple. We could do that together in 1.5hrs in Costa coffee&quot;</blockquote><p>...</p><blockquote>&quot;I literally want a one page with some info on it. The main thing is I want people to get to that page when they search for &quot;x&quot; or associated terms. the page will basically be my contact details and my services and fees. If I can do that via wix etc. that&apos;s a job ez&quot;</blockquote><h2 id="summary-checklist-of-actions">Summary checklist of actions</h2><ul><li>The requirements are very basic, however the person is not familiar with technology (so hire for advice / consultancy as needed if at all)</li></ul><p>Requirements</p><ul><li>To decide and <a href="https://domains.karmacomputing.co.uk/">buy a web address</a></li><li>Choose a web hosting provider</li><li>Consider <a href="https://karmacomputing.co.uk/page/email-hosting">business email hosting</a> for a professional email address using your web address </li></ul>]]></content:encoded></item><item><title><![CDATA[Terraform best practices - what I wish I'd learnt quicker]]></title><description><![CDATA[<p>Terraform has a changed over the years (it&apos;s HCL syntax changed a <em>lot </em>from the early days breaking backward compatibility) and there&apos;s a few Terraform concepts which, for me, are worth holding front-and-centre to reduce pain when working with the tool.</p><h1 id="if-you-have-existing-cloud-resources-approach-terraform-differently">If you have <em>existing </em>cloud</h1>]]></description><link>https://blog.karmacomputing.co.uk/terraform-best-practices-what-i-wish-id-learnt-quicker/</link><guid isPermaLink="false">646a33aab93427b5f9b1fd52</guid><category><![CDATA[devops]]></category><dc:creator><![CDATA[Christopher Simpson]]></dc:creator><pubDate>Sun, 21 May 2023 16:39:41 GMT</pubDate><media:content url="https://blog.karmacomputing.co.uk/content/images/2023/05/terraform-best-practices-shot-by-cerqueira-0o_GEzyargo-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.karmacomputing.co.uk/content/images/2023/05/terraform-best-practices-shot-by-cerqueira-0o_GEzyargo-unsplash.jpg" alt="Terraform best practices - what I wish I&apos;d learnt quicker"><p>Terraform has a changed over the years (it&apos;s HCL syntax changed a <em>lot </em>from the early days breaking backward compatibility) and there&apos;s a few Terraform concepts which, for me, are worth holding front-and-centre to reduce pain when working with the tool.</p><h1 id="if-you-have-existing-cloud-resources-approach-terraform-differently">If you have <em>existing </em>cloud resources, approach terraform differently</h1><p><br>Terraform really wants to not only have a complete graph of resources- Terraform expects to have been the tool that originally <em>created</em> all resources in your cloud provider from the onset. The &apos;ideal&apos; Terraform project one where you start from a empty cloud account to having all resources created by Terraform. This is the essence of infrastructure as code after-all. </p><p>You are very much going against the grain if you&apos;re trying to model <em>existing</em> resources which were created by hand, and attempt to &apos;import&apos; them into Terraforms&apos; view of the world. </p><p>Terraform&apos;s support for importing resources has always felt finicky, and for good reasons Terraform removed the <code>replace</code> command from it&apos;s cli. You may also be interested in <code>terraform import</code> command to <a href="https://developer.hashicorp.com/terraform/cli/import">import existing resources</a>. Even there though, this does not import all existing configuration- again, consider the prospect of rec-recreating the account resources from scratch programmatically. </p><p>Re-creating in a blank account may sound<em> </em>drastic but you may find yourself in a situation with hundreds (if not thousands) of resources which have been created over the years (most of which costing money) which are misconfigured, and not under version control anyway. </p><p>A pragmatic first step may be to &#xA0;</p><ul><li>create a git repo</li><li><a href="https://developer.hashicorp.com/terraform/language/state/remote">setup your terraform remote state</a></li><li>Plan the cloud resources genuinely needed</li><li>Write &amp; commit your terraform HCL to your git repo, starting with a few key required resources</li><li>perform your <code>terraform plan</code> and ultimate <code>terraform apply</code></li></ul><h1 id="there-may-be-existing-resources-you-dont-have-permission-to-see-%60iam%60">There may be existing resources you don&apos;t have permission to see (`iam`)</h1><p></p><p>A big gotcha to be aware of with with Terraform, and <em><strong>potential danger </strong></em>is visibility based on the authorisation level your cloud credentials (IAM) have. If the cloud account (e.g. GKE, AWS) keys you&apos;re using to connect to Terraform does not have all the access you need to administer the account, you may be performing a <code>terraform plan</code> / <code>terraform apply</code> with incomplete access to existing resources which can result in confusion. </p><p>Again, the above largely can occur if you&apos;re doing a cloud migration with a mix of <em>existing </em>cloud resources not managed by Terraform and others which are. <em> </em> </p><h1 id="too-much-nesting-with-foreach-and-modules">Too much nesting with <code>foreach</code> and modules</h1><p>It&apos;s tempting to get lost in the flexibility of Terraform modules, looping, nested modules- especially if you&apos;re modelling multiple availability zones / regions for failover. The reality is that it&apos;s still tricky to achieve those goals, and I suspect they are talked/blogged about more than practised. Instead, at least <em>start</em> with a long-form non-nested, no modules, long HCL script which describes your infrastructure. This goes against our DRY programming principles I know, but especially if you&apos;re new to terraform- don&apos;t abstract away too early. </p><h2 id="treating-terraform-like-a-programming-language">Treating Terraform like a programming language</h2><p>Terraform HCL is not a programming language, it&apos;s a <a href="https://github.com/hashicorp/hcl/blob/main/hclsyntax/spec.md">configuration language</a>. Don&apos;t make my mistake in treating Terraform HCL as a programming language, you&apos;ll &apos;configure&apos; yourself into a corner. The distinction is important- Terraform HCL is not a programming language, it&apos;s purpose in life is &quot;to safely and <strong><em>predictably</em></strong> provision and manage infrastructure&quot; . </p><p>If you allow arbitrary programming, you loose the ability to predictably re-create infrastructure. &#xA0;Yet, the pull is so strong to <em>program</em> infrastructure rather than <em>declare it</em>, nascent tools like <a href="https://www.pulumi.com/">Pulumi</a> exist where you can, if you so wish, <code>curl</code> the weather next week and provision different resources depending on that.</p><p>The <a href="https://en.wikipedia.org/wiki/KISS_principle">KISS principle</a> (keep it simple) saves you a lot pain. Tim Peters was right &quot;Flat is better than nested&quot;- even if that was a <a href="https://peps.python.org/pep-0020/">poem</a> about a different language.</p>]]></content:encoded></item></channel></rss>